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

一、 需求和文档 
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>
参与评论 您还未登录,请先 登录 后发表或查看评论
货运作业 货运作业总单 托运明细记录查询 物流统计 进仓单 出仓单 仓库记录 作业查询 库存记录 委托单位 经营单位 托运记录 车辆托运查询 托运明细记录查询 财务结算 货运作业结算总单 结算分单 费用统计表 仓库结算单 结算总单 结算单位查询 结算总目录 托运记录查询 所属车队车辆查询 报价 系统维护 公司资料设置 操作人员权限设置 更改密码 物流方式设置 委托单位设置 经营单位设置 到港名称设置 仓库名称设置 车辆资料管理 客户明细资料设置 传真 系统服务 备份数据 恢复数据 导出数据 导入数据货运物流管理系统(主菜单结构)├─货运作业│ ├─货运作业总单│ ├─托运明细记录查询│ ├─物流统计│ ├─进仓单│ ├─出仓单│ └─仓库记录├─作业查询│ ├─库存记录│ ├─委托单位│ ├─经营单位│ ├─托运记录│ ├─车辆托运查询│ └─托运明细记录查询├─财务结算│ ├─货运作业结算总单│ ├─结算分单│ ├─费用统计表│ ├─仓库结算单│ ├─结算总单│ ├─结算单位查询│ ├─结算总目录│ ├─托运记录查询│ ├─所属车队车辆查询│ └─报价├─系统维护│ ├─公司资料设置│ ├─操作人员权限设置│ ├─更改密码│ ├─物流方式设置│ ├─委托单位设置│ ├─经营单位设置│ ├─到港名称设置│ ├─仓库名称设置│ ├─车辆资料管理│ ├─客户明细资料设置│ └─传真└─系统服务 ├─备份数据 ├─恢复数据 ├─导出数据 └─导入数据 货运作业总单 ZY110托运明细记录查询 ZY120物流统计 ZY130进仓单 ZY210出仓单 ZY220仓库记录 ZY310库存记录 CX110委托单位 CX120经营单位 CX210托运记录 CX220车辆托运查询 CX310托运明细记录查询 CX320货运作业结算总单 JS110结算分单 JS210费用统计表 JS220仓库结算单 JS230结算总单 JS240结算单位查询 JS310结算总目录 JS320托运记录查询 JS410所属车队车辆查询 JS420报价 JS510公司资料设置 WH110操作人员权限设置 WH120更改密码 WH210物流方式设置 WH310委托单位设置 WH320经营单位设置 WH330到港名称设置 WH340仓库名称设置 WH350车辆资料管理 WH360客户明细资料设置 WH410传真 WH420备份数据 FW110恢复数据 FW120导出数据 FW210导入数据 FW220关于…… Help110 货运作业、作业查询、财务结算、系统维护、系统服务货运作业货运作业总单、托运明细记录查询、物流统计、进仓单、出仓单、仓库记录作业查询库存记录、委托单位、经营单位、托运记录、车辆托运查询、托运明细记录查询财务结算货运作业结算总单、结算分单、费用统计表、仓库结算单、结算总单、结算单位查询、结算总目录、托运记录查询、所属车队车辆查询、报价系统维护公司资料设置、操作人员权限设置、更改密码、物流方式设置、委托单位设置、经营单位设置、到港名称设置、仓库名称设置、车辆资料管理、客户明细资料设置、传真系统服务备份数据、恢复数据、导出数据、导入数据

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

指尖de柔情

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值