activiti自定義流程之Spring整合activiti-modeler5.16例項(二):建立流程模型
1.maven導包,這裡就沒有什麼多的好說了,直接程式碼:
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.0.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.0.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.0.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.0.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.0.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.0.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>4.0.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>4.0.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>4.0.9.RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.2.3</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.2.3</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.2.3</version> </dependency> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-modeler</artifactId> <version>5.16</version> </dependency> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-engine</artifactId> <version>5.16</version> </dependency> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-explorer</artifactId> <version>5.16</version> </dependency> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-rest</artifactId> <version>5.16</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.0.9.RELEASE</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.34</version> </dependency> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-spring</artifactId> <version>5.16</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.0.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.0.9.RELEASE</version> </dependency> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-bpmn-converter</artifactId> <version>5.16</version> </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-core-asl</artifactId> <version>1.9.11</version> </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>1.9.11</version> </dependency> </dependencies>
2.基礎配置:web.xml,這個也主要是spring相關的東西,不多說了:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <filter> <description>字符集過濾器</description> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <description>字符集編碼</description> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>RestletServlet</servlet-name> <servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class> <init-param> <param-name>org.restlet.application</param-name> <param-value>org.activiti.rest.editor.application.ModelerRestApplication</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>RestletServlet</servlet-name> <url-pattern>/service/*</url-pattern> </servlet-mapping> <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springMVC</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>activiti.html</welcome-file> <welcome-file>activiti.htm</welcome-file> <welcome-file>activiti.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> </web-app>
3.基礎配置spring.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:annotation-config /> <mvc:annotation-driven /> <context:component-scan base-package="controllers" /> <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://192.168.0.201:3306/testtu?useUnicode=true&characterEncoding=utf8" ></property> <property name="username" value="root" ></property> <property name="password" value="123456" ></property> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"> <property name="dataSource" ref="dataSource" /> <property name="databaseSchemaUpdate" value="true" /> <property name="jobExecutorActivate" value="false"/> <property name="history" value="full"/> <property name="transactionManager" ref="transactionManager" /> <!-- 配置事務管理器,統一事務 --> <!-- 設定建表策略,如果沒有表,自動建立表 --> </bean> <!-- 建立流程引擎物件 --> <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean"> <property name="processEngineConfiguration" ref="processEngineConfiguration" /> </bean> <!-- 由流程引擎物件,提供的方法,建立專案中使用的Activiti工作流的Service --> <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" /> <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService" /> <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService" /> <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService" /> <bean id="formService" factory-bean="processEngine" factory-method="getFormService" /> <!-- 避免IE執行AJAX時,返回JSON出現下載檔案 --> <bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/html;charset=utf-8</value> </list> </property> </bean> <!-- 啟動Spring MVC的註解功能,完成請求和註解POJO的對映 --> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messageConverters"> <list> <ref bean="mappingJacksonHttpMessageConverter" /><!-- json轉換器 --> </list> </property> </bean> </beans>
4.模型實體類:
package model;
import java.util.Date;
public class ActivitiModel {
private String id;
private String name;
private String key;
private String description;
private Date createTime;
private Date lastUpdateTime;
private int version;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getLastUpdateTime() {
return lastUpdateTime;
}
public void setLastUpdateTime(Date lastUpdateTime) {
this.lastUpdateTime = lastUpdateTime;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "ActivitiModel [id=" + id + ", name=" + name + ", key=" + key
+ ", description=" + description + ", createTime=" + createTime
+ ", lastUpdateTime=" + lastUpdateTime + ", version=" + version
+ "]";
}
}
5.後臺業務程式碼,這裡最後的操作是把跳轉到acitiviti-modeler流程圖設計介面的路徑返回到了前端,然後讓前端再跳轉到流程圖設計介面。
在我操作過程中,必須這樣做才能實現設想的結果,因為我的前端使用的是angular js,頁面上的路由跳轉也都是由angular ui來控制,所以像第一篇spring整合activiti-modeler中那樣從後臺直接重定向的話就沒有任何反應:
/**
* 建立模型
*
* @author:tuzongxun
* @Title: create
* @param @param activiti
* @param @param request
* @param @param response
* @param @return
* @return Object
* @date Mar 17, 2016 12:30:29 PM
* @throws
*/
@RequestMapping(value = "/create.do", method = RequestMethod.POST, produces = "application/json;charset=utf-8")
@ResponseBody
public Object create(@RequestBody ActivitiModel activiti,
HttpServletRequest request, HttpServletResponse response) {
Map<String, String> map = new HashMap<String, String>();
Boolean isLogin = this.isLogin(request);
if (isLogin) {
Model newModel = repositoryService.newModel();
try {
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode modelObjectNode = objectMapper.createObjectNode();
modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME,
activiti.getName());
modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION,
StringUtils.defaultString(activiti.getDescription()));
newModel.setMetaInfo(modelObjectNode.toString());
newModel.setName(activiti.getName());
newModel.setKey(StringUtils.defaultString(activiti.getKey()));
repositoryService.saveModel(newModel);
ObjectNode editorNode = objectMapper.createObjectNode();
editorNode.put("id", "canvas");
editorNode.put("resourceId", "canvas");
ObjectNode stencilSetNode = objectMapper.createObjectNode();
stencilSetNode.put("namespace",
"http://b3mn.org/stencilset/bpmn2.0#");
editorNode.put("stencilset", stencilSetNode);
repositoryService.addModelEditorSource(newModel.getId(),
editorNode.toString().getBytes("utf-8"));
} catch (Exception e) {
e.getStackTrace();
}
// response.sendRedirect(request.getContextPath() +
// "/service/editor?id="
// + newModel.getId());
map.put("isLogin", "yes");
map.put("userName",
(String) request.getSession().getAttribute("userName"));
map.put("path", "/service/editor?id=");
map.put("modelId", newModel.getId());
} else {
map.put("isLogin", "no");
}
return map;
}
6.angular js前臺程式碼,路由控制頁面跳轉:
(1).app.js:
$stateProvider
.state('create', {
url: "/create",
views: {
'view': {
templateUrl: 'activi_views/create.html',
controller: 'createCtr'
}
}
});
(2).createCtr.js,angular js中的控制器,和後臺互動,按我們公司前端現在的標準做法,應該還要服務層service,但是我運用還不太熟練,就暫且都放在controller中了:
angular.module('activitiApp')
.controller('createCtr', ['$rootScope','$scope','$http','$location','$state', function($rootScope,$scope,$http,$location,$state){
//建立模型
$http.post("createFlush.do").success(function(result){
if(result.isLogin==="yes"){
$rootScope.userName=result.userName;
}else{
$location.path("/login");
}
});
$scope.createTo=function(activiti){
//向後臺提交資料
$http.post("./create.do",activiti,{headers:'Content-Type:application/json'}).success(function(createResult){
console.log(createResult);
$location.path("/modelList");
window.open("http://localhost:8080/activitiTest1"+createResult.path+createResult.modelId);
});
}
}])
(3).index.html:
<!DOCTYPE html>
<html ng-app="activitiApp">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link href="./activi_css/activi.css" rel="stylesheet"/>
<link href="css/bootstrap/css/bootstrap.css?2023" rel="stylesheet" type="text/css" />
<link href="css/site.css?2023" rel="stylesheet" type="text/css" />
<script type="text/javascript">
var _root='http://form/index.php?s=/',_controller = 'index';
</script>
<script src="./angular-1.4.0-rc.2/angular.js"></script>
<script src='./angular-1.4.0-rc.2/angular-ui-router.js'></script>
<script src='./activi_js/app.js'></script>
<script src='./activi_js/createCtr.js'></script>
<script src='./activi_js/modelCtr.js'></script>
<script src='./activi_js/processCtr.js'></script>
<script src='./activi_js/taskCtr.js'></script>
<script src='./activi_js/loginCtr.js'></script>
<script src='./activi_js/hisTaskCtr.js'></script>
<script src='./activi_js/startProcessCtr.js'></script>
<script src='./activi_js/completeTaskCtr.js'></script>
</head>
<body style="width:100%;height:300px;margin:0;background-color:#fff">
<div style="height:70px;width:100%;border:1px solid #ccf">
<img id="rdiv" src="./images/activiti.png" style="width:30%;height:98%"/>
<a href="script:;" ng-show="userName!=undefined" style="margin-right:10px;float:right;margin-top:25px;" ng-click="logOut();">
[退出登陸]
</a>
<font ng-show="userName!=undefined" style="margin-right:10px;float:right;margin-top:25px;">當前登陸使用者:{{userName}}</font>
</div>
<div style="width:100%;position: absolute;height:auto">
<div style="height:580px;width:12%;font-size:36px;position:relative;float:left;border:1px solid #ccf" ng-show="userName!=undefined">
<table style="width:100%;text-align:center;margin-top:0px" cellSpacing="5px" cellPadding="0px">
<tr>
<td style="background-color:#caf;"><a href="#/create">建立模型</a></td>
</tr>
<tr>
<td style="background-color:#ccf;"> <a href="#/modelList">模型列表</a></td>
</tr>
<tr>
<td style="background-color:#cef;"><a href="#/processList">流程列表</a></td>
</tr>
<tr>
<td style="background-color:#aef;"><a href="#/taskList">當前任務</a></td>
</tr>
<tr>
<td style="background-color:#fef;"><a href="#/hisTask">歷史任務</a></td>
</tr>
</table>
</div>
<div ui-view="view" ></div>
</div>
</body>
</html>
(4).create.html:
<center>
<div style="margin-top:100px;margin-left:200px;background-color:#9cc;height:350px;width:40%;font-size:26px;position:relative;float:left;">
<p style="font-size:30px">建立模型</p>
Name :<input type="text" name="name" ng-model="activiti.name"/>
</br>
</br>
Key :<input type="text" name="key" ng-model="activiti.key"/>
</br>
</br>
Description:<input type="text" name="description" ng-model="activiti.description"/>
</br>
</br>
<input style="font-size:28px;cursor:pointer" type="button" value="建立模型" ng-click="createTo(activiti);">
<input style="font-size:28px;cursor:pointer" type="button" value="返回">
</div>
</center>
7.如果模型建立成功,則可以看到資料庫act_re_model中會出現一條資料,如下:
同時在act_ge_bytearray表中會出現兩條資料,如下圖:
並且可以看到,在model表中會有兩個欄位把bytearray表中兩條資料的id儲存起來。
相關推薦
activiti自定義流程之Spring整合activiti-modeler5.16例項(二):建立流程模型
1.maven導包,這裡就沒有什麼多的好說了,直接程式碼: <dependencies> <dependency> <groupId>junit</groupId> <artifact
activiti自定義流程之Spring整合activiti-modeler5.16例項(六):啟動流程
1.啟動流程並分配任務是單個流程的正式開始,因此要使用到runtimeService介面,以及相關的啟動流程的方法。我習慣於用流程定義的key啟動,因為有多個版本的流程定義時,用key啟動預設會使用最新版本。同時,因為啟動中查詢了流程部署時xml檔案中流程節點的資訊,也用
activiti自定義流程之Spring整合activiti-modeler5.16例項(五):流程定義列表
1.流程定義依舊屬於流程資源,因此查詢流程定義也還是使用repositoryService進行操作 2.後臺業務程式碼, (1)自定義的流程定義實體類:package model; pub
activiti自定義流程之Spring整合activiti-modeler5.16例項(一):環境搭建
專案中需要整合activiti-modeler自定義流程,找了很多資料後,終於成功的跳轉到activiti-modeler流程設計介面,以下是記錄: 一、整合基礎:eclipse4.4.1、tomcat7、jdk1.7、mysql5.6.25、maven3.2.5、acti
Spring整合Struts2和Hibernate+Maven(二)之SSH的配置檔案
上次講到的是maven專案的建立以及pom.xml的配置。 這裡推薦一個網站:maven整合jar包,這裡可以查詢並生成配置檔案中jar包匯入格式的文字,複製貼上到pom.xml中即可由idea自動下載並匯入專案。 resources資料夾 建立ssh的配置檔案至上章圖片中的res
實現自定義查詢的數據庫設計及實現(二)
表名 table abr bigint sts 處理 update 關聯表 creat 上部分大概講了一下表設計,這部分講一下處理。 處理的結構 處理結構的內容比較多,分為幾個部分分別講解一下。首先講解一下尋找關系表。 尋找關系表 尋找關系表根據“表間關系登記表”進行處
Spring Boot + Spring Cloud 構建微服務系統(二):服務消費和負載(Ribbon)
使用RestTemplate呼叫服務 在上一篇教程中,我們是這樣呼叫服務的,先通過 LoadBalancerClient 選取出對應的服務,然後使用 RestTemplate 進行遠端呼叫。 LoadBalancerClient 就是負載均衡器,預設使用的是 Ribbon 的實現 RibbonLoadBa
Spring Boot中使用WebSocket總結(二):向指定使用者傳送WebSocket訊息並處理對方不線上的情況
Spring Boot中使用WebSocket總結(二):向指定使用者傳送WebSocket訊息並處理對方不線上的情況 在上一篇文章(www.zifangsky.cn/1355.html)中我介紹了在Spring專案中使用WebSocket的幾種實現方式。但是,上篇文章中只介紹了服務端採用廣播模式給所有客戶
實戰容器程式設計好基友之visual studio code+docker篇(二):實時除錯執行在docker中的node.js程式
上篇文章中,我們介紹了怎麼利用visual studio code在本地編譯生成docker映象,這篇文章我們會介紹怎麼利用Visual studio code 實時除錯執行在容器中的node.js程式。 這裡我們還會利用之前的專案node-todo, 環境搭
GAN學習之路(二):遷移式模型
遷移變換 以CycleGAN為例,遷移就是從一個域遷移到另一個域。比如:斑馬到馬; 與CycleGAN很有關係的兩個兄弟DualGAN和DiscoGAN; CycleGAN的歷史淵源 階段一:cGAN,條件是標註資訊; 階段二:pix2pix,條件是圖片資訊;
【OpenCV入門教程之十一】 形態學影象處理(二):開運算、閉運算、形態學梯度、頂帽、黑帽合輯
上篇文章中,我們重點了解了腐蝕和膨脹這兩種最基本的形態學操作,而運用這兩個基本操作,我們可以實現更高階的形態學變換。所以,本文的主角是OpenCV中的morphologyEx函式,它利用基本的膨脹和腐蝕技術,來執行更加高階的形態學變換,如開閉運算、形態學梯度、“頂帽”、“黑帽
Spring整合Struts2和Hibernate+Maven(三)之請求的處理
關於請求的處理,即涉及前面提到Struts2。 具體流程:頁面發出請求->攔截action->處理action->具體到那個類的哪個方法處理。 頁面發出請求: fm.action="/Login_register"; fm.subm
Spring整合Struts2和Hibernate+Maven(一)之Maven專案建立
趁著畢設的功夫,寫一些東西。也算是記錄個人平時畢設完成的過程。 建立專案 工具:intellij idea+JDK1.6+Maven 第一步:New Project ->點選左側maven ->勾選Create fromarchetype 後選擇maven-archet
安卓專案實戰之強大的網路請求框架okGo使用詳解(二):深入理解Callback之自定義JsonCallback
前言 JSON是一種取代XML的資料結構,和xml相比,它更小巧但描述能力卻不差,由於它的小巧所以網路傳輸資料將減少更多流量從而加快了傳輸速度,目前客戶端伺服器返回的資料大多都是基於這種格式的,相應的我們瞭解的關於json的解析工具主要有兩個:Gson(Google官方出的)和fas
Spring Cloud Stream消費失敗後的處理策略(二):自定義錯誤處理邏輯
應用場景 上一篇《Spring Cloud Stream消費失敗後的處理策略(一):自動重試》介紹了預設就會生效的訊息重試功能。對於一些因環境原因、網路抖動等不穩定因素引發的問題可以起到比較好的作用。但是對於諸如程式碼本身存在的邏輯錯誤等,無論重試多少次都不可能成功的問題,是無法修復的。對於這樣的情況,前文
Activiti(二)簡單請假流程實現
在SpringBoot2整合Activiti6的環境中,實現簡單的請假流程。編寫請假業務流程。流程業務為: 1,員工請假,先建立請假流程 2,員工填寫請假申請,也可以不填寫,直接結束流程 3,提交給直接主管審批,如果直接主管拒絕,則重新填寫,如果直接主管同意,再到部門主
Android自定義元件之日曆控制元件-精美日曆實現(內容、樣式可擴充套件)
需求 我們知道,Android系統本身有自帶的日曆控制元件,網路上也有很多開源的日曆控制元件資源,但是這些日曆控制元件往往樣式較單一,API較多,不易於在實際專案中擴充套件並實現出符合具體樣式風格的,內容可定製的效果。本文通過自定義日曆控制元件,實現了在內容和樣
Spring Boot實現OAuth 2.0(二)-- 自定義許可權驗證
自定義攔截器進行許可權驗證 涉及到的姿勢: 自定義註解 攔截器 Spring Boot新增攔截器 文章目錄: 自定義註解 @Target(ElementType.METHOD)//作用在方法 @Retention(RetentionP
Angular自定義指令之scope屬性詳解及例項演示
本文將對AngularJS自定義指令詳解中的scope屬性配合例項演示,進行深度講解: scope屬性值可以是Boolean型別, 也可以是 Object型別, Boolean型別: scope值為false時,可以理解成指令內部並沒有一個新的sco
Spring-Cloud-Ribbon學習筆記(二):自定義負載均衡規則
lan cse 重新啟動 ping for obi .config 流行 prope Ribbon自定義負載均衡策略有兩種方式,一是JavaConfig,一是通過配置文件(yml或properties文件)。 需求 假設我有包含A和B服務在內的多個微服務,它們均註冊在一個E