宅急送 项目第六天 定区管理

1. 定区管理业务

定区管理 (和分区有何区别) :
区域管理针对自然行政区, 行政区域比较大,不可能让取派员去负责整个行政区域, 需要进行分区,将行政区域细分 ,成为很多小区域(分区), 需要为分区知道取派人员 , 在分配分区和取派员对应关系时, 可能几个取派员共同负责几个分区 (定区 )

定区就是 取派员 负责几个固定分区 物流取货和送货 !!
—- 定区 关联分区 、关联取派员
—- 定区 需要管理客户信息 ,当客户下单时 ,自动进行分单操作 (为客户自动找到负责取派人员 )

2. 添加定区

关联分区和取派员

这里写图片描述

2.1. 定区关联取派员

<input class="easyui-combobox" name="staff.id"                              data-options="valueField:'id',textField:'name',url:'${pageContext.request.contextPath }/staff_ajaxlist.action'" />  

在 StaffAction 中添加 ajaxlist的方法

<!-- 命名查询 -->
 <query name="Staff.findNoDelete">
    <![CDATA[from Staff where deltag = '0']]>
 </query>

配置返回结果

<!-- json列表,添加定区时使用 -->
<result name="ajaxlistSUCCESS" type="json">
    <param name="root">staffs</param>
    <param name="includeProperties">
        \[\d+\]\.id,
        \[\d+\]\.name
    </param>
</result>

2.2. 定区关联分区

使用datagrid ,显示所有未指定定区的分区

这里写图片描述

decidedzone_id is null 的分区

这里写图片描述

将 分区表格url 改为

 data-options="url:'${pageContext.request.contextPath }/subarea_findnoassociations.action'

在 SubareaAction 中添加 findnoassociations 方法

<!-- 命名查询 -->
<query name="Subarea.findassociations">
    <![CDATA[from Subarea where decidedZone is null]]>
</query>

配置返回结果

<!-- 关联定区列表 -->
<result name="findnoassciactionsSUCCESS" type="json">
    <param name="root">subareas</param>
    <param name="includeProperties">
        \[\d+\]\.id,
        \[\d+\]\.addresskey,
        \[\d+\]\.position
    </param>
</result>

2.3. 定区添加功能

<form id="decidedzoneForm"          action="${pageContext.request.contextPath }/decidedzone_saveOrUpdate.action" method="post">

点击保存按钮,提交form 表单

// 为添加修改定区 ,保存按钮 添加 click事件
$('#save').click(function(){
    // 提交前,先校验 form 输入
    if($('#decidedzoneForm').form('validate')){
        $('#decidedzoneForm').submit();
    }else{
        $.messager.alert('警告','表单存在非法数据项,请重新输入','warning');
    }
});

问题: 当form 提交时,定区编号和分区编号 冲突了

这里写图片描述

修改分区表格id 的field

<th data-options="field:'subareaId',width:30,checkbox:true">编号</th>
使返回分区数据json能够和field 关联
<!-- 关联定区列表 -->
<result name="findnoassciactionsSUCCESS" type="json">
    <param name="root">subareas</param>
    <param name="includeProperties">
        \[\d+\]\.subareaId,
        \[\d+\]\.addresskey,
        \[\d+\]\.position
    </param>
</result>

需要在Subarea类 提供 getSubareaId

public String getSubareaId() {
    return id;
}

这里写图片描述

编写定区管理Action —- DecidedZoneAction

public class DecidedZoneAction extends BaseAction implements ModelDriven<DecidedZone> {
}
public interface DecidedZoneService {
}
public class DecidedZoneServiceImpl extends BaseService implements DecidedZoneService {
}

将DAO 注入 BaseService
将Service 注入 BaseAction

业务代码

public void saveOrUpdate(DecidedZone decidedZone, String[] subareaIds) {
    // 保存定区数据
    decidedZoneDAO.save(decidedZone);
    // 实现定区和分区关联(用分区 对象 关联 定区 多方关联一方)
    for (String id : subareaIds) {
        Subarea subarea = subareaDAO.findById(id); // 分区持久对象
        subarea.setDecidedZone(decidedZone);
    }
}

配置

<!-- 定区管理 -->
<action name="decidedzone_*" class="decidedZoneAction" method="{1}">
    <!-- 添加保存 -->
    <result name="saveOrUpdateSUCCESS">
        /WEB-INF/pages/base/decidedzone.jsp
    </result>
</action>

3. 定区列表查询(分页查询)

分页列表查询,使用 PageRequestBean 和 PageResponseBean 、 BaseService 的 pageQuery 方法 !

$('#grid').datagrid( {
    url : "${pageContext.request.contextPath}/decidedzone_pageQuery.action",
});

在 DecidedZoneAction 添加 pageQuery 方法

<!-- 定区分页查询 -->
<result name="pageQuerySUCCESS" type="json">
    <param name="root">pageResponseBean</param>
    <param name="includeProperties">
        total,
        rows\[\d+\]\.id,
        rows\[\d+\]\.name,
        rows\[\d+\]\.staff\.name,
        rows\[\d+\]\.staff\.telephone,
        rows\[\d+\]\.staff\.station
    </param>
</result>

未完成 : 双击定区,查询关联分区

$('#association_subarea').datagrid( {
        url : "subarea_xxx.action",
        queryParams : {"decidedZone.id": rowData.id},

4. 定区关联客户(远程调用)

这里写图片描述

BOS的定区管理模块,需要定区关联客户的功能,实际中 客户数据在CRM系统中,BOS系统需要从CRM系统中获取数据,进行数据交互 !!!

4.1. RMI 技术分析

使用Hessian技术,完成BOS和CRM的系统整合
Hessian是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI(Java Remote Method Invocation 方法远程调用 )的功能。 相比WebService,Hessian更简单、快捷。采用的是二进制RPC((RemoteProcedureCallProtocol)——远程过程调用协议)协议,因为采用的是二进制协议,所以它很适合于发送二进制数据。

RMI 是 Java 首选远程调用协议,非常高效稳定,特别是在数据结构复杂,数据量大的情况下,与其他通讯协议的差距尤为明显。但不能跨语言

HttpInvoker 使用 java 的序列化技术传输对象,与 RMI 在本质上是一致的,不能跨语言
Hessian 性能比RMI 慢20% ,但是通过二进制传输,跨语言 
Burlap 采用 xml 格式传输。仅在传输 1 条数据时速度尚可,通常情况下,它的毫时是 RMI 的 3 倍。
WebService通讯毫时是 RMI 的 10 倍,传输xml数据,基于soap协议 (Axis2、 CXF )

这次定区关联客户功能,选择Hessian

下载网址: http://hessian.caucho.com/ hessian-4.0.33.jar

[2]Dubbo是[3]阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 [4]Spring框架无缝集成。

这里写图片描述

调用 淘宝和支付宝 的接口 ,通常使用 Dubbo ,Dubbo底层使用Hessian

4.2. 编写Hessian入门程序

Hessian.mht 使用文档

开发步骤 :
1、 建立服务器和客户端两个工程, 导入hessian的jar包
2、 服务器编写
定义业务接口

public interface HelloService {
    public String sayHello(String name);
}
public class HelloServiceImpl implements HelloService {
    @Override
    public String sayHello(String name) {
        return "hello hessian , name: " + name;
    }
}

将业务接口注册为一个Hessian服务

这里写图片描述

将myserver 发布到tomcat 运行

这里写图片描述

3、 编写客户端
如果是java客户端,直接将业务接口复制到客户端程序

这里写图片描述

编写客户端测试程序

// 编写Hessian客户端
String url = "http://localhost:8080/myserver/hello";
HessianProxyFactory hessianProxyFactory = new HessianProxyFactory();

// 创建接口代理程序
HelloService proxy = (HelloService) hessianProxyFactory.create(HelloService.class, url);
String result = proxy.sayHello("itcast");
System.out.println(result);

4.3. 使用Hessian 完成定区管理客户的功能

4.3.1. 定区关联客户功能分析

查询定区的列表

这里写图片描述

选择一个定区,点击上面 关联客户的按钮 ,需要显示form表单
查询所有未指定定区的客户 (查询CRM)
查询当前选中定区已经关联的客户 (查询CRM )

将 “关联客户form表单.txt” 整合 decidedzone.jsp 页面中

// 在关联客户的方法 
function doAssociations(){
    // 先判断用户是否选择 定区数据 
    var rowData = $('#grid').datagrid('getSelected');
    if(rowData == null){
        // 未选中
        $.messager.alert('警告','定区关联客户前,必须要先选中一个定区','warning');
    }else{
        // 已经选中
        // 显示关联客户的窗口
        $('#customerWindow').window('open');
    }
}

这里写图片描述

需要查询所有未关联定区的客户和 已经关联当前定区的客户

提交表单,将客户关联到定区上, 通过Hessian, 将定区信息保存到 CRM 中!

4.3.2. 编写CRM系统

新建 web project — crm
* 操作数据库 使用Hibernate 框架
* 提供远程服务 使用Hessian

导入jar包和配置文件

编写 Customer 实体类

这里写图片描述

编写 Customer.hbm.xml

这里写图片描述

在hibernate.cfg.xml 引入 hbm文件

<!-- 在核心配置文件中 引用 mapping 映射文件 -->
<mapping resource="cn/itcast/crm/domain/Customer.hbm.xml"/>

输入一些测试数据

这里写图片描述

根据业务编写业务接口

这里写图片描述

提供 CustomerServiceImpl 实现类

这里写图片描述

这里写图片描述

这里写图片描述

发布Hessian 服务, 配置web.xml

Hessian服务器端和客户端,进行发布时,都可以和Spring集成(整合)

参加 “Hessian - thinking-in-programming - Hessian配置步骤 - Think & Summing - Google Project Hosting.mht ”

这里写图片描述

访问 http://localhost:8080/crm/customerService

这里写图片描述

4.3.3. 编写BOS项目客户端代码

1、 导入 Hessian的jar包

<dependency>
    <groupId>com.caucho</groupId>
    <artifactId>hessian</artifactId>
    <version>4.0.33</version>
</dependency>

2、 编写Hessian客户端 (和Spring整合 )
如果 不整合Spring , 使用 HessianProxyFactory 为目标接口 建立代理
整合Spring
将 cn.itcast.crm.service 、 cn.itcast.crm.domain 复制 BOS项目

这里写图片描述

在applicationContext-remoting.xml 中配置Hessian客户端代理

这里写图片描述

3、 编写测试用例,远程接口调试
别忘了,要启动 CRM的Hessian服务!!
三个业务方法,全部调试通过

4.3.4. 定区管理客户功能实现

Maven 运行 mavenbos ,保证端口 不要和CRM 使用Tomcat端口相同 !

1、 弹出关联客户到定区窗口时,发起两次Ajax请求,获取未关联列表和选中定区已经关联列表 ,显示到关联Select 元素中

$.post("${pageContext.request.contextPath}/decidedzone_findNoAssociationCustomers.action", function(data){
$.post("${pageContext.request.contextPath}/decidedzone_findHasAssociationCustomers",{id : rowData.id}, function(data){

发起两次Ajax请求 ,需要在DecidedZoneAction 添加两个业务方法

将customerService 注入 BaseAction !!
配置返回结果

<!-- 查询未关联 客户信息-->
<result name="findNoAssociationCustomersSUCCESS" type="json">
            <param name="root">customers</param>
</result>
<!-- 查询已经关联 客户信息-->
<result name="findHasAssociationCustomersSUCCESS" type="json">
                <param name="root">customers</param>
</result>

这里写图片描述

2、 关联操作 左右移动

<input type="button" value="》》" id="toRight"><br/>
<input type="button" value="《《" id="toLeft">

为左移和右移添加点击事件

// 添加左右 移动关联客户事件
$('#toRight').click(function(){
    // 将未关联 移到 已经关联
    $('#associationSelect').append($('#noassociationSelect option:selected'));
});
$('#toLeft').click(function(){
    $('#noassociationSelect').append($('#associationSelect option:selected'));
});

3、 点击关联客户,提交form表单

// 点击关联客户,提交表单
$('#associationBtn').click(function(){
    // 关联select 中所有option 选中
    $('#associationSelect option').attr('selected','selected');
    // 提交表单     $('#customerDecidedZoneId').val($('#grid').datagrid('getSelected').id); // 为定区隐藏域设置id 
    $('#customerForm').submit();
});

服务器 在 DecidedZoneAction 添加关联的方法 !

其它

课后资料

这里写图片描述

定区关联客户(分布式系统数据集成)

这里写图片描述

课程视频内容

这里写图片描述

这里写图片描述

二、完善其余功能节点 -- 流程 1、 将 提供其余节点页面 复制 pages/zhongzhuan 入库(点击左侧菜单入库) ----- Action (查询入库任务列表)---- instore_list.jsp ---- 办理任务 ---- instore_complete.jsp(提交form) --- Action (办理任务流转到下一个节点) 修改function 数据表 入库 task_findInStoreTask.action 出库 task_findOutStoreTask.action 签收 task_findReceiveInfoTask.action 2、 查询任务列表 TaskAction // 业务方法 ----- 查询入库环节 的个人任务 public String findInStoreTask(){ // 登陆用户 User user = (User) getSession().getAttribute("user"); List<ZhongZhuanInfo> zhongZhuanInfoList = myTaskService.findTransferTask(user,"入库"); // 值栈 ActionContext.getContext().put("zhongZhuanInfoList", zhongZhuanInfoList); return "findInStoreTaskSUCCESS"; } // 业务方法 ----- 查询出库环节 的个人任务 public String findOutStoreTask(){ // 登陆用户 User user = (User) getSession().getAttribute("user"); List<ZhongZhuanInfo> zhongZhuanInfoList = myTaskService.findTransferTask(user,"出库"); // 值栈 ActionContext.getContext().put("zhongZhuanInfoList", zhongZhuanInfoList); return "findOutStoreTaskSUCCESS"; } // 业务方法 ----- 查询签收环节 的个人任务 public String findReceiveInfoTask(){ // 登陆用户 User user = (User) getSession().getAttribute("user"); List<ZhongZhuanInfo> zhongZhuanInfoList = myTaskService.findTransferTask(user,"配送签收"); // 值栈 ActionContext.getContext().put("zhongZhuanInfoList", zhongZhuanInfoList); return "findReceiveInfoTaskSUCCESS"; } 3、 配置struts.xml结果页面 <result name="findInStoreTaskSUCCESS">/WEB-INF/pages/zhongzhuan/instore_list.jsp</result> <result name="findOutStoreTaskSUCCESS">/WEB-INF/pages/zhongzhuan/outstore_list.jsp</result> <result name="findReceiveInfoTaskSUCCESS">/WEB-INF/pages/zhongzhuan/receiveinfo_list.jsp</result> 4、 Action办理对应节点任务 // 业务方法 ---- 办理入库任务 public String instorecomplete(){ InStore inStore = new InStore(); inStore.setInfo(info); inStore.setUpdateTime(new Date()); // 调用业务层 myTaskService.completeInStore(taskId, inStore); return "instorecompleteSUCCESS"; } // 业务方法 ---- 办理出库任务 public String outstorecomplete(){ OutStore outStore = new OutStore(); outStore.setInfo(info); outStore.setUpdateTime(new Date()); // 调用业务层 myTaskService.completeOutStore(taskId, outStore); return "outstorecompleteSUCCESS"; } // 业务方法 ---- 办理签收任务 public String receiveinfocomplete(){ ReceiveGoodsInfo receiveGoodsInfo = new ReceiveGoodsInfo(); receiveGoodsInfo.setInfo(info); receiveGoodsInfo.setUpdateTime(new Date()); // 调用业务层 myTaskService.completeReceiveGoodsInfo(taskId, receiveGoodsInfo); return "receiveinfocompleteSUCCESS"; } 5、 struts.xml 跳转回任务列表 <result name="instorecompleteSUCCESS" type="redirectAction">task_findInStoreTask</result> <result name="outstorecompleteSUCCESS" type="redirectAction">task_findOutStoreTask</result> <result name="receiveinfocompleteSUCCESS" type="redirectAction">task_findReceiveInfoTask</result> 在JBPM在流程结束时,发生异常 org.springframework.dao.DataIntegrityViolationException: could not delete: [org.jbpm.pvm.internal.model.ExecutionImpl#50001]; SQL [delete from JBPM4_EXECUTION where DBID_=? and DBVERSION_=?]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not delete: [org.jbpm.pvm.internal.model.ExecutionImpl#50001] 解决: hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect ======================================================================================================================== 三、 流程实例 查看管理 1、 查询实例功能 查询系统正在运行实例 ExecutionService.createProcessInstanceQuery() 查询系统已经完成的实例 HistoryService.createHistoryProcessInstanceQuery() json/admin/json { id:1005, pId:100, name:"查看正在运行的任务", t:"",page:"page_workflow_processinstance.action"} 改为 { id:1005, pId:100, name:"查看正在运行的任务", t:"",page:"processinstance_list.action"} 2、 每个运行流程实例,关联流程变量 ZhongZhuanInfo 包含所有流程信息 根据流程实例id 查询ZhongZhuanInfo数据 (ZhongZhuanInfo) processEngine.getExecutionService().getVariable(pid, "zhongZhuanInfo"); 服务器返回 中转信息 result = zhongZhuanInfo.toString(); <result name="showInfoSUCCESS" type="json"> <param name="root">result</param> </result> 在页面抓取中转信息,回显 $.post("${pageContext.request.cotnextPath}/processinstance_showInfo.action", {"pid": pid}, function(data){ $.messager.alert("流程实例信息", data, "info"); }); 3、 实例运行的流程图查看 需要在流程图上面 标记每个 流程运行到哪个任务节点 第一步: 为每条实例记录,添加查看流程图函数 <a href="#" class="easyui-linkbutton" onclick="showPng('<s:property value="#processInstance.id"/>');">查看流程图</a> function showPng(pid){ alert("查看" + pid + "对应流程图"); } 第二步: 流程图查看Action 可以复用 ---- processdefinition_showpng.action?deploymentId= & resourceName= RepositoryService.getResourceAsStream(java.lang.String deploymentId, java.lang.String resourceName) * resourceName 可以通过 deploymentId 动态获得 RepositoryService repositoryService = processEngine.getRepositoryService(); ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).uniqueResult(); resourceName = processDefinition.getImageResourceName(); 第三步: 点击查看流程图, 获得活动节点坐标 通过 window.showModalDialog() 查看流程图页面 (弹出窗口,显示页面 url地址不能修改 ) function showPng(pid){ //alert("查看" + pid + "对应流程图"); window.showModalDialog("${pageContext.request.contextPath}/processinstance_findactivityinfo.action?pid="+pid); } 查看某一个具体活动节点坐标 String processDefinitionId = "test-1"; // 流程定义的id String activityName = "start1"; // 活动的名称 ActivityCoordinates c = processEngine.getRepositoryService() .getActivityCoordinates(processDefinitionId, activityName); 查看当前流程实例活动所有节点名称 ProcessInstance的 java.util.Set<java.lang.String> findActiveActivityNames() @Override public List<ActivityCoordinates> findActivityCoordinates(String pid) { // 1、 根据流程实例id 获得所有活动节点名称 ProcessInstance processInstance = processEngine.getExecutionService().createProcessInstanceQuery().processInstanceId(pid).uniqueResult(); Set<String> activityNames = processInstance.findActiveActivityNames(); // 2、一个活动节点 --- 对应一个坐标对象 List<ActivityCoordinates> activityCoordinates = new ArrayList<ActivityCoordinates>(); for(String activityName: activityNames){ // 获得每一个活动节点名称 String processDefinitionId = processInstance.getProcessDefinitionId();//流程定义id ActivityCoordinates activityCoordinate = processEngine.getRepositoryService().getActivityCoordinates(processDefinitionId, activityName); activityCoordinates.add(activityCoordinate); } return activityCoordinates; } ============ 为了在下一个页面 可以显示流程图, 根据实例id 查询 发布id @Override public String findDeploymentIdByProcessInstanceId(String pid) { ProcessInstance processInstance = processEngine.getExecutionService().createProcessInstanceQuery().processInstanceId(pid).uniqueResult(); ProcessDefinition processDefinition = processEngine.getRepositoryService().createProcessDefinitionQuery().processDefinitionId(processInstance.getProcessDefinitionId()).uniqueResult(); return processDefinition.getDeploymentId(); } <img src="${pageContext.request.contextPath }/processdefinition_showpng.action?deploymentId=<s:property value="#deploymentId"/>" style="position: absolute;top: 0;left: 0"/> <s:iterator value="#activityCoordinates" var="activityCoordinate"> <div style="width: <s:property value="#activityCoordinate.width"/>px; height: <s:property value="#activityCoordinate.height"/>px; left: <s:property value="#activityCoordinate.x"/>px; top: <s:property value="#activityCoordinate.y"/>px; position: absolute; border-color: red; border-style: solid; border-width: 1px;"> </s:iterator>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值