宅急送项目开发过程及问题?

一、 需求和文档 
1、 项目类型 
OA : 办公自动化(Office Automation,简称OA)是将现代化办公和计算机网络功能结合起来的一种新型的办公方式 
CRM : CRM(Customer Relationship Management)即客户关系管理 通常所指的CRM,是指用计算机自动化分析销售、市场营销、客户服务以及应用支持等流程的软件系统
ERP : ERP是Enterprise Resource Planning(企业资源计划)的简称, ERP是针对物资资源管理(物流)、人力资源管理(人流)、财务资源管理(财流)、信息资源管理(信息流)集成一体化的企业管理软件
CMS :网站内容管理系统, 即 Content Management System ,英文缩写是CMS。 网站内容管理系统具有许多基于模板的优秀设计,可以加快网站开发的速度和减少开发的成本。 

宅急送物理系统 是ERP子系统 

2、 项目相关介绍
研发时间2010 二期工程 ,采用CS架构 
针对二期系统需求,使用 B/S 制作 

规模: 20多个工程师 ,不到3个月时间  (企业通常"人月" 概念计算项目规模  ----- 60人月)  ------- 300-400万项目

3、 项目文档: 
项目经验: 项目需求、如何实现 
文档: 宅急送新业务系统流程说明书-整合版.doc 

软件开发流程 : 宅急送公司公开招标(金蝶、用友 ) ----- 中标后成立项目组 (项目经理、需求分析工程师、开发人员 页面设计工程师、美工、Java工程师、测试工程师) ------- 需求人员整理整理需求 
**  文档: 宅急送新BOS系统软件需求规格说明书.doc ----- (作业: 阅读引言 系统管理之前部分 )

Java工程师,接触到最高文档 通常需求文档 ------------- 系统原型 (假数据页面) 、 详细设计 、 开发编码 

4、 功能分为三大模块: 公共信息模块 、 取派(业务受理、货物调度、返货)、中转业务(货物进出库 )、 路由管理 (运输工具,进出港)

====================================================================================
二、 技术选型 
初级工程师,刚入职 系统后期维护升级  (基于原有系统的功能追加 )

小公司项目经理 ===== 项目经理 + 技术经理 + 架构师 

大公司 
项目经理 : 管理项目 (人力、财务、项目进度、和客户沟通 偏销售) ---- 零技术  (团队管理)
架构师: 技术选型、难题攻关 , 保证技术方案在项目组可实施  (技术管理 )
技术经理 (组长): 带手下人干活的 ,确保手下的人任务能够完成 

技术选型 : 
项目三层结构: web层解决方案、业务层解决方案、数据层解决方案 
任何公司: 长期开发,积累自定义组件  

流程技术: struts2 + spring3 + hibernate3  
运行平台: 版本管理 SVN  +  Linux (服务器环境部署 )  + tomcat7.0 + JDK7  + Oracle 
开发环境: window + tomcat7.0 + JDK7 + mysql 

UI设计 : jquery easy ui  
服务器端 : 任务调度(定时器) quartz 、 表单HTML在线编辑器(所见即所得)、报表 Open Flash Chart 、 JBPM 、 excel解析 POI  

三、技术预热阶段 
1、 struts2 + spring3 + hibernate 
便捷性 : 首选注解开发 
熟练度 : 配置文件 

struts2 框架使用  blank.war中所有jar包、 struts2-spring-plugin.jar 、 (使用注解 struts2-convetion-plugin.jar) 
*** 非注解 web.xml  struts.xml 
***  注解  web.xml  @Action 

在实际开发中为了位置文件 更好维护, 创建单独source folder  -----------  config 
在实际开发中经常需要单体测试 ,需要将测试代码 与功能代码分开,也可以采用创建 单独source forlder -------------  test 

spring3 框架使用  core、aop、tx、jdbc、dao、test 、web 、log 
**  在config下 导入log4j.properties
**  在config下 创建applicationContext.xml  jdbc.properties 
**  Hibernate 实体类都是用注解 开发 
配置数据源 、Hibernate实体类 通过packageToScan 自动扫描、 事务管理器TransactionManager、 使用注解管理事务 

配置 web.xml  ContextLoaderListener 

Hibernate框架使用  hibernate3.jar 、required/*.jar、 jpa.jar 、log4j 、 二级缓存 
***  将Hibernate 配置写入Spring中 applicationContext 

问题: struts2是直接与客户端交互,需要编写jsp文件,如何对jsp做权限控制 ? 
* 方案一 : 如果jsp在WebRoot下,url直接访问到,通过Filter 进行权限控制 
* 方案二 : 将jsp 放入WEB-INF下 ,页面url不能直接访问 ,通过struts2 的Action转发给 jsp  (因为经过Action,通过拦截器进行权限控制)
使用方案二,该Action没有什么逻辑,只是单纯跳转  -------  默认处理类 
 <default-class-ref class="com.opensymphony.xwork2.ActionSupport" /> 

<action name="page_*">
<result>/WEB-INF/pages/{1}.jsp</result>
</action> 

问题: 客户端使用Ajax访问struts2 , struts2如何返回一个json数据 
* 方案一: json-lib
* 方案二: flexjson  

AJAX过程中,请使用火狐查看通信过程中数据,调试js ---- firebug 经常使用console.info(信息);  (类似System.out )

json-lib 
**** TODO : json-lib 序列化日期对象出现异常  
如果两个对象互相关联,在序列化过程中 ,  net.sf.json.JSONException: There is a cycle in the hierarchy!  ---- 解决 JsonConfig 设置某个属性不进行序列化

flexjson 
导入 flexjson.jar 
JSONSerializer jsonSerializer = new JSONSerializer();
String result = jsonSerializer.serialize(customers); ------ 默认只会序列化当前对象,关联Order没有被序列化
String result = jsonSerializer.deepSerialize(customers); ----- 深度序列化,将关联对象序列化 

jsonSerializer.exclude("*.class"); // 不对getClass属性进行序列化  
** 没有日期问题 

问题: 业务层进行事务管理 ? 
使用Hibernate, 将sessionFactory对象注入 HibernateTransactionManager , 有该对象进行事务控制 
<tx:annotation-driven transaction-manager="transactionManager"/>  使用注解来管理事务  ------- 在需要管理事务类或者方法上 @Transactional 
***** 进行事务管理 通常Service层 

事务管理 @Transactional 属性 isolation 隔离级别  propagation 传播行为 read-only 设置事务只读 timeout 设置事务超时 

问题: 通常锁编写代码会针对业务层进行测试
@RunWith(SpringJunit4LoaderRunner.class)
@ContextConfiguration("location: classpath:applicationContext.xml")
public XxxServiceTest {
@Autowired
private XxxService xxxService;

@Test
public void testRegist(){
}
}

问题: 架构系统时,是否使用接口 ? 
在业务层、数据层都会定义接口 , 统一规范 ,分层开发 
* 许多外包公司,按层划分任务 
* 开发过程中 ,Action依赖Service、Service依赖DAO  ,使用接口进行分层开发 , 例如:web层只需要调用接口编程, 业务层只需要考虑接口实现 
* 便于维护 

问题: 数据层 ,将使用 HibernateTemplate 进行操作 。 模板提供的很多方法都使用泛型 
例如: 
将一个数据对象,保存到数据库 this.getHibernateTemplate().save(Object);  ------ 可以用来对各种数据类型进行保存 
修改 update() 
删除 delete
查询 get/load 根据id查询,查询所有 find , 条件查询 findByCriteria 

将重复操作,抽取一个公共类 GenericDAO<T> extends HibernateDaoSupport 
*****  接口和抽象类的区别 ??? 
// 增加
public void save(T obj);
// 删除
public void delete(T obj);
// 修改
public void update(T obj);
// 查询
public T findById(Class<T> domainClass ,Serializable id); // 如果id自增,定义为Integer 或者 Long
public List<T> findAll(); // 查询所有
public List<T> findByCriteria(DetachedCriteria criteria);// 各种各样条件查询, 添加排序 
public List<T> findByCriteria(DetachedCriteria criteria, int firstResult , int maxResults); // 分页查询 
public List<T> findByNamedQuery(String namedQuery); // 进行条件查询,使用hql, 在业务层调用NamedQuery名称就可以了 

使用注解配置Customer和Order
@Table(name="orders")
public class Order {
@Id
@GenericGenerator(name="uuidGenerator", strategy="uuid")
@GeneratedValue(generator = "uuidGenerator")
private String id ;
private String addr;
@ManyToOne(targetEntity=Customer.class)
@JoinColumn(name="customer_id")
private Customer customer ;

@Entity
@Table(name="cutomers")
public class Customer {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id ;
private String name; 
// mappedBy 相当于 inverse,将外键权利交给对方
@OneToMany(targetEntity=Order.class,mappedBy="customer")
private Set<Order> orders = new HashSet<Order>();

====================================================================================
四、bos项目构建 
分为三个资源包: src 源码、 config配置文件 、test测试用例 
整合: 将action配置到struts.xml 、 applicationContext.xml 主要配置业务层和数据层 、数据源、 事务管理 ------ 将applicationContext.xml 分为service 、dao

编写代码时:将struts的action配置struts.xml , 将service配置到service.xml  将dao 配置到dao.xml 

action、service、dao 都是使用xml配置, 实体类domain使用注解(省略hbm文件)
* 允许注入时,使用Autowired注解  (使用Autowired 需要 <context:annotation-config /> )

客户端前台页面 ------------------------- 使用jquery easyui 前端框架 
为什么要使用easyui ? 很多团队,工程师主要是服务器端工程师,不熟悉页面开发  ------- CSS很差
** 很多前端UI框架,自带CSS模板,即使java工程师也可以写出非常漂亮的界面 

为什么不用ExtJS? 要用EasyUI ?   
因为ExtJS框架比较庞大,引入后,系统性能有问题,比较慢, EasyUI 轻量级js前端框架 

你知道EasyUI 收费吗? 
1.2.2  版本之前,使用 GPLv3 协议 , ,开源组织协议  ----- 免费 
1.2.3  之后 GPL License Commercial License 

使用版本1.3.2  --------- 去下载该版本easyui  (是一套基于Jquery的前端UI框架,作用在于快速构建前端界面)
需要导入到工程的文件: 
1、 locale 国际化信息文件
2、 plugin 所有插件 js文件
3、 theme 主题CSS 
4、 jquery-1.8.0.min.js jquery核心包
5、 jquery.easyui.min.js 所有插件的合集 ====== plugins 里所有js 
6、 easyloader.js 可以根据代码选择plugin中的插件 

easyloader.js + plugin  ===  jquery.easyui.min.js  
学习曲线: 布局layout 

<script type="text/javascript"
src="${pageContext.request.contextPath }/js/jquery-1.8.0.min.js"></script>   ------------ jquery核心js 
<script type="text/javascript"
src="${pageContext.request.contextPath }/js/easyui/jquery.easyui.min.js"></script>  -------- easyui核心js 
<script type="text/javascript"
src="${pageContext.request.contextPath }/js/easyui/locale/easyui-lang-zh_CN.js"></script> ----- 国际化信息
<link id="easyuiTheme" rel="stylesheet" type="text/css"
href="${pageContext.request.contextPath }/js/easyui/themes/default/easyui.css">  ------ easyui核心css
<link rel="stylesheet" type="text/css"
href="${pageContext.request.contextPath }/js/easyui/themes/icon.css"> -------- 图标css

第一种 页面代码使用HTML编写,用easyui渲染,第二种 使用js 生成页面html 

布局layout分为 东西南北中 ----- 中是必须的 ,东西南北都可以省略 。

二、完善其余功能节点 -- 流程 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、付费专栏及课程。

余额充值