如果想要获取相关的源码,笔记,和相关工具,对项目需求的二次开发,可以关注我并私信!!!
一 昨天的内容复习-->供货商药品目录表结构分析
供货商药品目录表结构分析
上面的两张表需要完成两部分功能:
1. 供货商对供货商药品目录进行维护(增、删、改、查),操作的是供货商药品目录表:gysypml表来完成功能。
1.1 供货商向供货商药品目录添加一个药品(下节完成的功能),表示要供应此药品.表示向gysypml表插入一条记录,
同时也向Gysypml_contro表中插入(添加)一条记录(插入时必须要校验:如果此供货商药品已存在则不再插入),
向Gysypml_contro表中插入记录是为了监管单位对供货商药品进行控制!!
1.2 供货商从供货商药品目录删除药品,表示不再供应药品.此时从gysypml表删除一条记录.
(注意:此时不需要从Gysypml_control删除记录了,可以看优化后的结果。如果删除了那么监管单位卫生
局又该如何控制呢?)
1.3 供货商查询自己药品目录的信息(昨天的文档中已经完成了)。
查询条件中必须指定供货商id,因为只能查询出某个供货商的药品目录信息(这个很好理解)!
2. 监督单位对供货商药品目录进行控制。操作的是供货商药品目录控制表(Gysypml_control)来实现功能的。
2.1 监管单位要向供货商药品目录控制表插入记录,为了进行控制.
由于供货商向供货商药品目录添加一个药品同时向控制表也插入一条记录,因此添加功能就不需要了(优化后的结果)!
这是在开发的过程中总结出来的经验,不然两张表都有进行增删改查的话会很麻烦!!
2.2 监管单位从供货商药品控制表删除记录,表示监管单位不再对供货商药品进行控制.
优化:此功能不需要开发了,监管单位不再控制,只需将供货商药品供货状态改成“正常”(放行).
这是在开发的过程中总结出来的经验,不然两张表都有进行增删改查的话会很麻烦!!
监管单位更改供货商药品的供货状态.
监管单位对供货商供应的药品进行控制。(1:正常供货、2:暂停供货)
3. 两个状态:
供货商药品的供货状态:指监管单位对某个供货商的某个供应的药品进行供货状态控制。
药品交易状态:系统中药品目录表(药品总表ypxx)交易状态为暂停,表示此药品不在本系统流通,监督单位
不再监管此药品,供货商不再供货,医院无法采购。
药品目录操作由卫生局进行维护。
4. 小结:
如果医院进行药品采购,需要满足什么条件?
医院会从本区域的供货商药品目录中来查找药品进行采购,而找到的药品必须监管单位允许供货商供货,且此药品的交易状态为“正常”。
二 供货商药品目录维护的批量添加功能的提交实现(难点)
1 需求分析
用户在供货商药品目录添加查询页面,然后选择多个药品,确认添加。如图:
1.1 2个前置条件
2个前置条件(即service层中的约束条件,这两个约束条件可以参考下面的service层实现类中的代码来理解):
1)先要明确一点:在弹出的“供货商药品添加”下的“供应药品列表”中的药品信息是供货商药品目录表gysyoml中所没有的药品信息!
换句话说说:供货商只允许添加(插入)药品目录中所没有的药品。
2) 药品的交易状态为暂停时则不允许添加,这个条件考虑了用户的体验度的问题!因为登录该系统的用户身份是供应商,无论该药品信息的交易 状态是正常还是暂停,你需要把供应商药品目录中所没有的药品信息都展示出来方便供应商来添加药品信息,这是为了后续不必要的麻烦!
所以还是有必要把交易状态为暂停的药品信息也展示出来!
等到供应商选择好要添加的药品信息,然后点击“确定添加按钮时”,如果该药品的交易状态为暂停则再提示此药品信息交易状态为暂停不允许添加时, 也不迟!
简单说,一切是为了用户的体验度!!!
1.2 后置条件(数据库操作)
向供货商药品目录表gysypml插入一条记录,
同时也向供货商药品目录控制表gysypml_control插入一条记录.
1.3 页面中的操作
用户需要选择多个药品,进行批量添加。
2 批量添加的技术分析和测试(难点)
2.1 问题一:Service层插入多条记录的异常处理如何解决
如果接收的是插入的多条记录,就需要在service中自己进行多条记录的异常处理;
因为,如果不在service接口进行异常处理,会导致一条记录的添加失败会导致其它记录的回滚,因为插入操 作是在一个事务中进行的!!!
这样会导致之前定义的全局异常处理器失去了作用!你就需要自定来定义一个异常处理器了(很麻烦)
2.2 问题二:添加失败的处理
如果批量添加失败,就需要给用户提示失败原因(并且是多个失败原因),而失败原因的提示应该在action 来 实现,service层来处理异常信息是不太恰当的!
2.3 最终解决方案
对于以上两个问题,我们提示出了Service接口的终极解决方案:
Service接口只处理一条记录的插入,然后在 action方法内通过循环调用service来进行批量处理;
如果service层中如果遇到异常则只管向上抛出到action层中,action层捕获异常信息并可以灵活组织用户的提示信息
2.4 Action如何接收前台页面中传过来的批量数据
2.4.1在包装类GysypmlQueryVo中添加List属性
在前台页面向后台的action传递批量数据的过程中,由于后台使用的是springmvc,那么后台的action方法中就必须使用List集合(确切的说:使用的是包装类GysypmlQueryVo中定义的List类型的属性)来接收前台页面提交的批量数据。(可以参考 “springmvc高级知识.doc”文档中的List参数绑定!)
注意:这个List集合属性中存储的是前台页面提交过来的全部数据,包括选中和不选中的业务数据!!!
那么,就必须要在包装类GysypmlQueryVo中添加List属性,List属性中是自定义的POJO类,定义如下:
2.4.2 action方法中使用List集合来接收自定义的pojo
本系统的action方法使用是包装类GysypmlQueryVo中定义的List集合类型的属性来接收页面提交批量数据,List集合中是自定义的pojo!!!(参考“测试”一节中的定义)
最终Action中方法的定义如下:
红框内的GysypmlQueryVo包装类就是用来接收页面中提交的全部的业务数据,包括选中和没选中的所有数据!
2.5 前台页面的数据准备
前台页面queryaddgysypml.jsp中需要准备两种类型的数据来传到后台action中:
第1个是页面中的业务数据的定义。(这两部分都已经在queryaddgysypml.jsp中定义好了,下面只是分析如何定义的。)
第2个是前台页面中获取的被选中的行的序号。
2.5.1 queryaddgysypml.jsp页面中的业务数据是如何定义的呢?
定义:list属性名[序号从0开始].属性(list中pojo的属性名).(参考“springmvc高级知识.doc”文档中的List参数绑定)假设,页面中提交的业务数据的定义如下:
上面的定义只是假设,实际上在queryaddgysypml.jsp页面中,在datagrid的列定义中定义了一个input标签的hidden属性,用来存储药品信息id值,如下:
这样,就解决了页面中提交批量数据的问题!并将所有的Hidden对象传递到了后台的aciton类中的方法中的包装类GysypmlQueryVo中!
2.5.2 queryaddgysypml.jsp页面中如何获取选中行的序号呢
那就需要使用datagrid的相关方法和属性来获取!!!
按照如上的业务数据定义的格式,就会将页面中定义的所有Hidden对象都传到后台的action中的包装对象中。
问题是:你需要的只是把页面中所有选中行的数据传递到后台的action的包装对象中,而这又是由页面中所定义的
checkbox标签所决定的。因此,还需要将页面中所有选中的行号传入到后台的action中!!!(步骤如下)
假如页面中的checkbox标签中选择第一条和第三条条记录,那么就会将页面上选中的行的序号(index)传递到action中所定义的int[]数组中!如图:
最终在queryaddgysypml.jsp页面中获取选中行的序号的实现步骤如下:(该页面中的内容都已经定义好了,这里的步骤只是分析如何实现的)
第1步
第2步
datagrid组件提供的getSelections()方法和getRowIndex()方法能正常执行的前提条件是,如图:
这里的idField属性必须要设置正确,否则就会无法获得选中行的序号!当然,这一句在页面中已经得到了正确的设置!
第3步:
其中的红框内的对象indexs就是第4步中定义的id=”indexs”对象,获取该indexs对象后中间以逗号分隔并赋值!
第4步:在queryaddgysypml.jsp页面的form表单中定义了input标签用来存储选中行的序号,如下:
第5步:最终由在springmvc.xml文件中如下定义的
该注解驱动会把页面中定义的以逗号分隔的字符串数组indexs自动进行解析,而后台的action方法中只需使用indexs形参数组来接收即可!如下:
queryaddgysypml.jsp页面中完整的datagrid组件的使用参考源码吧!
2.6数据测试
2.6.1前台页面的测试
可以在queryaddgysypml.jsp页面中添加一条测试语句,如图:
{ field : 'id', hidden:true, formatter:function(value, row, index){ //index是每行的序号,ypxxCustoms是action中接收的list集合对象名称,ypxxid是list中对象的属性名 return '<input type="hidden" name="ypxxCustoms['+index+'].id" value="'+value+'" /><input type="hidden" name="ypxxCustoms['+index+'].mc" value="'+row.mc+'" />'; } } |
然后,queryaddgysypml.jsp页面中可以添加一个alert断点(测试结束该断点可以删除了),如图:
选中要添加的药品信息,然后点击“添加”,就会把选中的序号打印出来,如图:
则表示页面中的测试成功!
2.6.2后台YpmlAction.java中的测试
想要保证后台的包装对象GysypmlQueryVo中能正常的接收前台传递过来的数据,需要在该包装对象中有如下的定义:
测试Indexs中的值是否是你选中行的值!
3 DAO实现
使用逆向工程生成的两张表的代码已经生成了。参考昨天的day05中的内容!
因此只需要使用逆向工程生成的代码执行插入即可!
4 Service实现
见过上面的“技术分析”可知,service层要处理单条记录的插入。并且,service层中还要对两个前置条件进行约束判断!
接口功能:向供货商药品目录ghsypml表中添加一个药品.
接口参数:usergysid供货商id、ypxxid药品id.
YpmlService.java接口的源码看项目吧,如图:
一共有3个方法:
其中,findGysypmlByUsergysidAndYpxxid()方法和findGysypmlControlByUsergysidAndYpxxid()两个方法是针对insertGysyoml()方法的封装!之所以要把这两个方法单独的封装起来是为了在其他的service接口中方便的调用!
YpmlServiceImpl.java实现类,看源码,如图:
实现类中的校验条件可以参考“需求”!
5 Action实现(模板代码)
模板代码是指:在下面的“供货商药品目录维护的批量删除”的功能实现中的action的实现可以参考这里的action实现!
在前台页面中的批量提交的数据中:
Usergysid:供货商id的有且只有一个id,因为你使用的是供应商身份信息登录的系统。因此后台的action方法从可以从session中获取登录的身份信息!
Ypxxid:药品id有一个或者多个,因为页面中选择的是一个或多个数据来,然后后台action方法中包装类 GysypmlQueryVo中定义的list属性来接收。
在YpmlAction中添加如下方法:
6 JSP页面实现(难点)
queryaddgysypml.jsp页面已经在上面的“技术分析”中说到过,直接复制该页面到项目中即可,这里再捋一遍该页面的执行流程!
下面的3个步骤可以参考页面中的如下方法:
当用户点击“确认添加”按钮时,:
1)执行确认添加的事件,如下:
然后,调用datagrid的getSelections获得所有选中的行,如图:
再然后,将选中行的序号解析出来,最后,以逗号拼接存入indexs的input中
2)在datagrid的列定义中定义了hidden,来存储药品信息id值
其实,value的值也可以用返回的Json的key是id的值来代替,如下写法:
3) 通过ajax的form提交 .
将indexs值(页面选中行的序号)提交到action。
将ypxxCustoms(提交的批量业务数据)提交到action.
7 供货商药品目录的批量添加提交调试
在调试之前需要把gysypml表和gysypml_control表中的数据都清除掉,这样才可以更好的测试!
执行如下图的的两条sql语句:
别忘了提交事务,如下:
一定要以九州通供货商(ghsjzt)的身份来登录系统,因为还没有实现权限管理的功能,如下:
如果不是供货商身份来登录系统的话,当执行插入操作时,系统会提示“未知错误”.
7.1 插入失败的原因的展示问题
先插入3条“交易状态为正常”的记录,测试不会有任何问题。
但是,当选取3条暂停交易的和一条正常交易的商品信息进行添加,会出现如图所示:
问题:失败原因不详细!你不知道为何失败!
解决步骤如下:
当然,复制过来的页面就已经把这个问题解决了,这里说一下解决问题的步骤
第1步:将queryaddgysypml.jsp页面中的提交回调方法中message_alert(data);改为:_alert(data)方法
_alert(result)方法会将失败的详细信息展示出来
第2步:需要将action返回的submitResultinfo中添加details属性(该属性中存储了失败原因),如图的红框内的修改
修改完代码后的最终效果如下:
注意:在service抛出异常信息时,尽量详细!!
!即:在YpmlServiceImpl的insertGysypml()方法中如下的异常信息中要包含流水号和通用名:
7.2 只允许提交当前页的数据的问题
目前为止的提交功能只支持在当前页中选中记录后再提交是没有任何问题的。
但是如果在当前页中选中了记录后,再翻下一页,在下一页中选中记录后,再提交就会出现-1。
如图所示的断点调试结果:
解决方法:
在翻页时,清除之前所有选中的行。
当然,该页面中的问题在复制该页面时就已经解决,下面的代码也已经被添加上了!
这里分析一下解决这个问题的方式。
需要在queryaddgysypml.jsp添加如下的两个地方:
第1个地方
第2个地方
再测试的结果就是:不管上一页中选中了几条记录,如果翻到下一页后又选中了记录,然后再提交,那么,上一页中的数据就会清空,后台的action中的index参数只接受下一页的数据的序号!!
断点调试!!
7.3 添加后的页面刷新问题
在queryaddgysypml.jsp页面中添加如下:
当然,该页面是复制过来的,这个问题已经解决了,方法如下
三 供货商药品目录维护的批量删除实现
1 需求
供货商对于不再供应的药品从供货商的药品目录中来删除
约束条件:
对于一个具有需求规格说明书(给程序员看的)的项目,以下两个方便必须要有的:
约束条件:此药品在供货商药品目录表gysypml中存在方可删除。
数据库操作:从供货商药品目录表gysypml中删除记录即可。
不需再要从供货商药品目录控制表gysypml_control中删除记录了,因为在“供货商药品目录模块的设计”一节的优化方案已经分析的很清楚了!
2 Dao
根据药品信息id(ypxxic)和供货商id(usergysid)删除供货商药品目录表gysypml中的记录,因为在gysypml表中这两条记录确定唯一性约束!如图:
因为是针对单表的操作,所以可以使用逆向工程所生成的代码,来将供货商药品目录表记录删除。
3 Service
接口功能:根据药品信息id和供货商id删除供货商药品目录表gysypml中的记录!
接口参数:药品信息id(ypxxic)和供货商id(usergysid)!这两个是业务字段,业务层就要使用用业务字段,这是规范!
接口实现的步骤:先校验约束条件:校验要删除的药品是否在供货商药品目录中存在,存在才可删除!
- 执行数据库的删除操作:调用mapper,根据主键删除(删除之前先根据供货商id和药品id查询出主键).
- 执行数据库的删除操作:调用mapper,根据主键删除(删除之前先根据供货商id和药品id查询出主键).
YpmlService接口添加如下方法
YpmlService接口的实现类YpmlServiceImpl中的添加如下方法:
4 Action
YpmlAction中的编写的方法实现参考:上面编写的“供货商药品目录维护的批量添加提交实现”功能中的方法addgysypmlsubmit()来实现,可以复制该方法的大部分代码即可(因为是一个模板方法)。
因为执行的是批量删除的操作,那么页面中需要传递如下的两个参数:
- 供货商id:页面中传递的是单个参数(因为当前的登录的用户身份是供货商,可以从session中来取出供货商id).
- 药品id:页面传递的是多个参数(页面中可以选择多个,那么定义格式:hidden,list[].XXX).
5 querygysypml.jsp页面
一般开发中,编写页面和action的同一个人!
在供应商药品目录维护页面querygysypml.jsp中需要注意以下几个地方
第1个,批量参数药品id()的定义:将药品id在datagrid列中定义hidden,
红框内是注意的地方
第2个:Datagrid的json主键定义:
使用datagrid的getSelections获取当前所有选中的行,要求Datagrid定义时指定json结果集的唯一约束,如图
红框内的定义
第3个:Js方法的定义:
Form表单提交的url地址必须正确,如下:
6 调试
以供货商身份登录系统
假设要删除流水号为“108427”的药品,选中后删除,如图
删除后再查询该流水号的药品信息,如果查询不到,说明删除成功!如下图: