Key points:
1. Review the JBPM workflow development process
2. Complete the transit distribution process
3. Process instance monitoring module
4. Exception handling
5. L2 cache
1. Review of JBPM development process
1.1. Integrating the Workflow Framework in the Project (Day 9)
Import the jar package (import using maven coordinates)
Configuration file jbpm.cfg.xml The core configuration file, the hibernate configuration file jbpm.hibernate.cfg.xml is imported by default, if Spring is integrated,
<import resource="jbpm.tx.spring.cfg.xml" />
the hibernate configuration power is handed over to Spring
to introduce hbm
<value>jbpm.repository.hbm.xml</value>
<value>jbpm.execution.hbm.xml</value>
<value>jbpm.history.hbm.xml</value>
<value>jbpm.task.hbm.xml</value>
<value>jbpm.identity.hbm.xml</value>
Spring integrates JBPM and needs to create a ProcessEngine process engine through the SpringHelper factory class
<!-- 整合jbpm 配置 -->
<bean id="springHelper" class="org.jbpm.pvm.internal.processengine.SpringHelper">
<property name="jbpmCfg" value="jbpm.cfg.xml"></property>
</bean>
<bean id="processEngine" factory-bean="springHelper"
factory-method="createProcessEngine" />
Note:
1. For MySQ integration, you need to use the
org.hibernate.dialect.MySQL5InnoDBDialect dialect
. 2. JBPM relies on the juel jar package, which will conflict with the /lib/el-api.jar released by tomcat. Solve the problem by placing the three jars in tomcat/lib , do not put in the project WEB-INF/lib
1.2. Process definition management (not related to business)
1.2.1. You can deploy the business process to the project through the module and upload the zip archive
1.2.2. Process Design
Online designer and offline designer, generate jpdl.xml and png through design, deploy online designer directly, offline designer need to upload zip archive!
1.2.3. Process Definition View
1.2.4. Flowchart View
1.3. How to start the process?
Different business processes start in different ways
In the transit distribution process, through the work order approval function, approve the work order and start the transit process
Started by key, the process with the highest version of the same key is started by default.
In the process instance, associate the process variable ZhongZhuanInfo, and associate the corresponding data of all task nodes in the process
1.4. Task node, who will handle it
Task node, use the candidate-groups group task management method (to use swimlanes according to the business)
to associate system user role management with JBPM users and groups!
Add system users, add JBPM users,
add system roles, add JBPM user groups
, grant roles to users, and complete the establishment of JBPM user and group relationships
1.5. Task handling
Group Task View - Pick up Group Task View - Personal Task - Personal Task Handling
1.5.1. How to display the process instance variable information in the page
The server queries the task list List<Task>
, but the Task interface does not have a method to obtain process variables. Use TaskImpl to implement the class API to display process business data!
1.5.2. In the task list, all the corresponding tasks of the process are displayed. If you jump to a different page to handle it?
Through the <task>
node form attribute, execute the task handling form (page), obtain the form page through the Task object, and when you click handle, jump to a different page for handling
1.5.3. How does the server operate when handling tasks
Associate business data with PO objects for persistence
Associate business data with process instances,
handle tasks, and automatically circulate
When handling transit tasks, use free-flow technology (dynamic transition) to flow to any node through the current node
Interview question: If the process has been written and a new node needs to be added to the process, how to do it?
Option 1: Modify the flowchart, republish, version +1, start the process again to use the new process definition (problem, the original process cannot use the new process definition)
Option 2: Modify the published process definition, save the data in the jbpm4_lob table, which is binary blob, first read blob through data, become InputStream, use dom4j to load into memory, use dom4j to add new nodes to the process, echo the memory data to the lob table, and the process is modified
2. Complete the remaining node tasks of the transit distribution process
The three task nodes of warehousing, warehousing, and delivery and receipt are handled
When handling inbound tasks, jump to instore_complete.jsp
When handling outbound tasks, jump to outstore_complete.jsp
When handling delivery and receipt tasks , jump to receiveinfo_complete.jsp
Write the business code handled by the three task nodes Into the
warehouse , TaskAction provides the storecomplete method
Outbound: TaskAction provides the outstorecomplete method
Delivery and receipt: TaskAction provides the receiveinfocomplete method
Inject inStoreDAO, outStoreDAO, receiveGoodsInfoDAO into BaseService
Example code for handling warehousing tasks:
Configure result set
<result name="instorecompleteSUCCESS" type="redirectAction">task_findpersonaltask</result>
<result name="outstorecompleteSUCCESS" type="redirectAction">task_findpersonaltask</result>
<result name="receiveinfocompleteSUCCESS" type="redirectAction">task_findpersonaltask</result>
3. Process instance management module
Question: How do I view running instances that are running? How to check the completed process? How to view process instance variables? How does the process instance run to which node?
View running process instance information, jbpm4_execution table - ExecutionService
View completed process instance information, jbpm4_hist_procinst table—HistoryService
3.1. View running process instance information
/WEB-INF/pages/workflow/processinstance.jsp Process instance list page
Modify the admin.jsp system menu
{ "id":"1005", "pId":"100", "name":"查看正在运行的任务",
"t":"","page":"processinstance_list.action"}
Write server code ProcessInstanceAction
public class ProcessInstanceAction extends BaseAction {
}
Write a list method to view information about all running process instances
// 获得ExecutionService
ExecutionService executionService = processEngine.getExecutionService();
ProcessInstanceQuery query = executionService.createProcessInstanceQuery();
List<ProcessInstance> processInstances = query.list();
Configure result set
<!-- 流程实例管理 -->
<action name="processinstance_*" class="processInstanceAction" method="{1}">
<result name="listSUCCESS">/WEB-INF/pages/workflow/processinstance.jsp</result>
</action>
Question: Can I display business data when displaying a list of process instances?
ProcessInstance interface does not provide business data display method, you can see ExecutionImpl implementation class API
When displaying business data, control datagrid to wrap automatically
3.2. Instance flow chart view
In addition to displaying the flowchart, draw a red marker box to mark the current node
3.2.1. Popup window, display page
function show(processInstacneId){
// 弹出页面
window.showModalDialog("${pageContext.request.contextPath}/processinstance_showpng.action?processInstacneId="+processInstacneId);
}
First, according to the instance id, query the release id and image name
Add showpng method in ProcessInstanceAction
jump viewpng.jsp
<result name="showpngSUCCESS">/WEB-INF/pages/workflow/viewpng.jsp</result>
3.2.2. Referring to the flowchart through the img tag
<img src="${pageContext.request.contextPath }/processdefinition_viewpng.action
?deploymentId=${deploymentId}&imageResourceName=${imageResourceName}" />
3.2.3. Drawing a red marker box
Get the current task node coordinates from JBPM, and draw the red box
provided by RepositoryService
Question: How many currently active nodes does a process have?
Not necessarily one, because fork/join
get event name
4. Exception handling strategy in project development
4.1. Exceptions can be configured with friendly error pages
4.1.1. Configure web.xml
<error-page>
<error-code>404</error-code>
<location>/404.jsp</location>
</error-page>
4.1.2. Configuring error pages in struts.xml
<global-exception-mappings>
<exception-mapping result="error" exception="java.lang.Exception"></exception-mapping>
</global-exception-mappings>
<!-- 配置全局结果集 -->
<global-results>
<result name="error">/error.jsp</result>
</global-results>
Problem: Just use friendly pages, control user experience, handle exceptions, not flexible enough and fine-grained
4.2. Using the proxy mechanism, struts2 defines interceptors to control exceptions
public class MyExceptionInterceptor extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation invocation) throws Exception {
String result = null;
try {
result = invocation.invoke();
} catch (Exception e) {
// 进行异常的捕获和处理
result = "error";
}
return result;
}
}
<interceptor-stack name="privilegeStack">
<interceptor-ref name="myexception"></interceptor-ref> <!-- 异常拦截器配置到最前端 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="login"></interceptor-ref>
<interceptor-ref name="privilege"></interceptor-ref>
</interceptor-stack>
In the exception interceptor, after an exception occurs, perform detailed processing (record logs, send emails)
4.3. In enterprise development, if an exception occurs in the Service layer and the DAO layer, what are the catch and throws?
Can solve the exception, catch and solve
If exception cannot be solved, is it thrown directly? negative
For example, an SQL exception occurs in the DAO layer and is thrown to the Service layer. The Service layer has no ability to solve the problem. The
enterprise will first catch the exception and convert it into a business operation exception and throw it.
MoneyNotEnoughException Insufficient balance exception
When a specific business exception is thrown, the upper layer knows how to deal with it!
4.4. The server handles ajax and non-ajax requests differently
Non-ajax request, return error page
ajax request, return json exception information
According to the request header information
to distinguish whether it is an ajax request
// 判断是否为ajax请求
if (ServletActionContext.getRequest().getHeader("X-Requested-With") != null) {
// ajax 请求
Map<String, Object> map = new HashMap<String, Object>();
map.put("result", "failure");
map.put("msg", "修改密码失败," + e.getMessage());
ActionContext.getContext().put("map", map);
result = "errorjson";
} else {
result = "error";
}
Configure json result page
<result name="errorjson" type="json">
<param name="root">map</param>
</result>
5. The application of the second level cache in the project
5.1. Analyzing L2 Cache Applications
Question: What is the second level cache? How is the second level cache stored? How is the second level cache used?
Hibernate provides a first-level cache (Session scope) and a second-level cache (SessionFactory scope), the first-level cache is built-in,
SessionFactory caches two parts of content, one part of cfg file, hbm file configuration content (named query), the other part of data cache (need to configure, refer to external framework)
Level 2 cache, support EhCache, OSCache, JBOSS Cache
Session cache can only be used in one thread. In development, bind Session to thread, one thread corresponds to one Session,
The data in the Session cannot be requested by multiple users, and different user requests cannot be shared. The SessionFactory is used for caching to realize multiple users and share data between multiple requests.
Level 2 cache, which stores data stored in bulk objects and accesses the data in the level 2 cache. The query condition is id!
What is the difference between query cache and second level cache? The second level cache caches the entire object attribute data, the query condition is id, the query cache can cache any query result, and the query condition is the SQL statement
Use of L2 cache:
1. Introduce jar package
2. Introduce configuration file
3. Enable L2 cache in hibernate
4. Configure L2 cache provider
5. Configure caching strategy
BOS project application scenario: Each user logs in, needs to query the user's roles and permissions, and save it to the session. The user's role information will be repeated, and the role's corresponding permission information will also be repeated.
5.2. Using the second level cache in the project
Take EhCache as an example
5.2.1. Import the jar package
Use maven to import the jar package of ehcache
<!-- 导入二级缓存 -->
<!-- ehcache -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>1.5.0</version>
</dependency>
<!-- 导入二级缓存提供商 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>3.6.10.Final</version>
</dependency>
5.2.2. Introducing EhCache configuration file
Find
it Copy the ehcache-failsafe.xml in the jar to the project resources directory and rename it ehcache.xml
5.2.3. Enable L2 cache
Configure applicationContext-common.xml
<!-- 开启二级缓存 -->
<prop key="hibernate.cache.use_second_level_cache">true</prop>
5.2.4. Configuring the L2 Cache Provider
<!-- 配置二级缓存实现(提供商) -->
<prop key="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</prop>
5.2.5. What data is configured to cache?
Configure the data cache concurrency strategy.
It can be configured in the cfg file and in the hbm file.
The cache is divided into class-level and collection-level caches
Configure Role.hbm.xml
<!-- 关联 -->
<set name="functions" table="role_function">
<cache usage="read-write"/>
<key column="role_id"></key>
<many-to-many class="cn.itcast.bos.domain.auth.Function" column="function_id"></many-to-many>
</set>
Collection-level caching, relying on class-level caching
Configure Function.hbm.xml
<class name="cn.itcast.bos.domain.auth.Function" table="auth_function">
<cache usage="read-write"/>
5.3. Preparing test data
Two roles role1 role2, three users aaa bbb ccc
aaa and bbb belong to role1, ccc belongs to
role2 role1 and role2 permissions are crossed
5.4. Configure log4j to only open the second level cache log and close other logs
log4j.rootLogger=OFF, stdout
log4j.logger.org.hibernate.cache=debug
5.5. Performance Monitoring of L2 Cache
<!-- 开启hibernate 二级缓存性能监控 -->
<prop key="hibernate.generate_statistics">true</prop>
Obtain monitoring parameters through the SessionFactory API
// 统计对象
Statistics statistics = sessionFactory.getStatistics();
System.out.println("命中次数:" + statistics.getSecondLevelCacheHitCount() + ", 丢失次数:" + statistics.getSecondLevelCacheMissCount());
other
Pre-class information
There are a lot of related technical information