1.首先在jContractList页面中增加两个改变状态的按钮(上报和取消)
action中的代码:
public String submit(){ return chState(1);//1是上报,0是取消 } //状态变为取消 public String cancle(){ return chState(0);//1是上报,0是取消 } private String chState(int curValue){ ContractDAO oDao = (ContractDAO) this.getDao("daoContract");//获得ContractDAO对象 String [] ids = model.getId().split(", "); Set<Contract> oSet = new HashSet<Contract>(); for (String id : ids) { //用页面modeldriven对象传过来的id去查,每个id查到的每条记录都改变为由curValue传过来的状态值 Contract obj = (Contract) oDao.get(Contract.class, id); obj.setState(curValue); oSet.add(obj); } //用集合封装是为了在这里批量修改,这里的保存方法要用参数为集合的 oDao.saveOrUpdateAll(oSet); return list(); }
在
jContractList
遍历生产厂家的字段添加操作按钮
<td class="tableHeader">操作</td>
在遍历的值上添加货物的超链接
<td> [<a href="contractProductAction_tocreate?contract.id=${id}">货物</a>] </td>
这里超链接的后面要加上购销合同的id,通过购销合同的id到合同产品明细表中就可以查询到这个购销合同包含的所有货物
也就是将来要传到隐藏域中的值。
新增ContractProductAction,不要忘记要配置好entity和struts的配置文件
ContractProductAction里面tocreate()的代码:
public String tocreate(){ //这是用超链接传过来的购销合同id去合同商品表里查货物的数据(超链接里的购销合同id当然是从数据库中查出来的) ContractProductDAO oDao = (ContractProductDAO) this.getDao("daoContractProduct"); //获得DAO对象 List<ContractProduct> dataList = oDao.find("from ContractProduct o where o.contract.id='"+ model.getContract().getId() +"'"); //某个合同下的所有货物 ActionContext.getContext().put("dataList", dataList); return "pcreate"; }
在新增页面里面加入合同中所有货物的列表是为了能让客户直观得看到购销合同中到底包含了哪些货物。
因为是新增,所以需要在页面上多一个下拉菜单,这个下拉菜单是显示所有生产厂家,为了能让用户选新增的货物到底是哪个厂生产的,所以tocreate()完整的代码如下:
public String tocreate(){ //清除不需要回显的内容 model.setFactory(null); //准备显示所有生产厂商的下拉菜单 FactoryDAO xDao = (FactoryDAO) this.getDao("daoFactory");//获取生产厂商DAO对象 List<Factory> factoryList = xDao.find("from Factory o where o.state=1");//获取所有生产厂商 ActionContext.getContext().put("factoryList", factoryList);//将生产厂商放入map域 //准备商品列表 ContractProductDAO oDao = (ContractProductDAO) this.getDao("daoContractProduct"); //获得合同商品明细表DAO对象 List<ContractProduct> dataList = oDao.find("from ContractProduct o where o.contract.id='"+ model.getContract().getId() +"'"); //这是用modeldriven传过来的购销合同id去合同商品表里查货物的数据 ActionContext.getContext().put("dataList", dataList); return "pcreate"; }
以下是jsp页面代码:(jContractProductCreate.jsp)
只有两个表格中的代码
<table class="commonTable" cellspacing="1"> <tr> <td class="columnTitle">货号:</td> <td class="tableContent"><input type="text" name="productNo"/></td> <td class="columnTitle">生产厂家:</td> <td class="tableContent"> <s:select name="factory.id" list="#factoryList" listKey="id" listValue="factoryName" headerKey="" headerValue="--请选择--"></s:select> </td> </tr> <tr> <td class="columnTitle">装率:</td> <td class="tableContent"><input type="text" name="loadingRate"/></td> <td class="columnTitle">包装单位:</td> <td class="tableContentAuto"> <input type="radio" name="packingUnit" value="PCS" class="input" checked/>只 <input type="radio" name="packingUnit" value="SETS" class="input"/>套 </td> </tr> <tr> <td class="columnTitle">数量:</td> <td class="tableContent"><input type="text" name="cnumber"/></td> <td class="columnTitle">单价:</td> <td class="tableContent"><input type="text" name="price"/></td> </tr> <tr> <td class="columnTitle">箱数:</td> <td class="tableContent"><input type="text" name="boxNum"/></td> <td class="columnTitle">排序号:</td> <td class="tableContent"><input type="text" name="orderNo"/></td> </tr> <tr> <td class="columnTitle">货物描述:</td> <td class="tableContent"><input type="text" name="productDesc"/></td> </tr> </table> <table id="ec_table" border="0" cellspacing="0" cellpadding="0" class="tableRegion" width="98%" > <thead> <tr> <td class="tableHeader"><input type="checkbox" name="selid" οnclick="checkAll('id',this)"/></td> <td class="tableHeader">序号</td> <td class="tableHeader">货号</td> <td class="tableHeader">货物描述</td> <td class="tableHeader">生产厂家</td> <td class="tableHeader">装率</td> <td class="tableHeader">包装单位</td> <td class="tableHeader">数量</td> <td class="tableHeader">箱数</td> <td class="tableHeader">单价</td> <td class="tableHeader">总金额</td> <td class="tableHeader">操作</td> </tr> </thead> <tbody class="tableBody" > <s:iterator value="#dataList" var="dl" status="lineNo"> <tr class="odd" οnmοuseοver="this.className='highlight'" οnmοuseοut="this.className='odd'" > <td><input type="checkbox" name="id" value="${id}"/></td> <td><s:property value="#lineNo.index+1"/></td> <td>${productNo}</td> <td>${productDesc}</td> <td>${factory.factoryName}</td> <td>${loadingRate}</td> <td>${packingUnit}</td> <td>${cnumber}</td> <td>${boxNum}</td> <td>${price}</td> <td>${amount}</td> <td> [<a href="contractProductAction_toupdate?id=${id}">修改</a>] [<a href="contractProductAction_delete?id=${id}&contract.id=${contract.id}">删除</a>] [<a href="extCproductAction_tocreate?contractProduct.id=${id}&contractProduct.contract.id=${contract.id}">附件</a>] </td> </tr> </s:iterator> </tbody> </table>
其中,还有一个很重要的隐藏域,用来记录jsp页面中带过去的购销合同的id,用于将来在新增或者修改页面点保存的时候知道是保存进那个购销合同,作为货物表的外键。
代码如下:
<body> <form name="icform" method="post"> <input type="text" name="contract.id" value="${contract.id}">
暂不设置为隐藏域是因为方便开发者测试
接下来做货物的修改:
在新增页面下面的货物列表中,加一列超链接:
<a href="contractProductAction_toupdate?id=${id}">修改</a>
把修改的货物的id带过去,告诉action修改的是那一个货物。
在action中的代码:
public String toupdate(){ //准备下拉列表数据 FactoryDAO fDao = (FactoryDAO) this.getDao("daoFactory"); List<Factory> factoryList = fDao.find("from Factory o where o.state=1"); //1启用 ActionContext.getContext().put("factoryList", factoryList); ContractProductDAO oDao = (ContractProductDAO)this.getDao("daoContractProduct"); //这里是通过货物id去或货物表查询单个货物,查出来的是对象,所以用get ContractProduct obj = (ContractProduct)oDao.get(ContractProduct.class, model.getId()); //把查到的对象压栈,一般对象压栈,list放入map域中 ActionContext.getContext().getValueStack().push(obj); return "pupdate"; }
以下是jsp代码:
<table class="commonTable" cellspacing="1"> <tr> <td class="columnTitle">货号:</td> <td class="tableContent"><input type="text" name="productNo" value="${productNo}"/></td> <td class="columnTitle">生产厂家:</td> <td class="tableContent"> <s:select name="factory.id" list="#factoryList" listKey="id" listValue="factoryName" headerKey="" headerValue="--请选择--"></s:select> </td> </tr> <tr> <td class="columnTitle">装率:</td> <td class="tableContent"><input type="text" name="loadingRate" value="${loadingRate}"/></td> <td class="columnTitle">包装单位:</td> <td class="tableContentAuto"> <!--这里是判断数据库的值,是pcs就是只,是sets就是套--> <input type="radio" name="packingUnit" value="PCS" class="input" <s:if test="packingUnit=='PCS'">checked</s:if>/>只 <input type="radio" name="packingUnit" value="SETS" class="input" <s:if test="packingUnit=='SETS'">checked</s:if>/>套 </td> </tr> <tr> <td class="columnTitle">数量:</td> <td class="tableContent"><input type="text" name="cnumber" value="${cnumber}"/></td> <td class="columnTitle">单价:</td> <td class="tableContent"><input type="text" name="price" value="${price}"/></td> </tr> <tr> <td class="columnTitle">箱数:</td> <td class="tableContent"><input type="text" name="boxNum" value="${boxNum}"/></td> <td class="columnTitle">排序号:</td> <td class="tableContent"><input type="text" name="orderNo" value="${orderNo}"/></td> </tr> <tr> <td class="columnTitle">货物描述:</td> <td class="tableContent"><input type="text" name="productDesc" value="${productDesc}"/></td> </tr> </table>
隐藏域代码如下:
<body> <form name="icform" method="post"> <input type="text" name="id" value="${id}"> <input type="text" name="contract.id" value="${contract.id}">
下面解释以下为什么是conract.id
首先,设置这个值是用来保存货物信息并且将货物信息再保存到购销合同中的,那么首先明确一下点击货物以后,进入货物的显示列表,这是模型驱动里面存的就是货物表的信息,也就是表ContractProduct中的所有属性,那么在这张货物表中保存货物id很简单,只要将属性值id带去action就行,也就是input的第一行为什么id前面没有前缀的原因。那么保存货物到货物表以后,还要把货物表中的信息保存到购销合同中,那么货物表和购销合同表的关联就是货物表中有一个字段contract,就是为了建立和购销合同的关联,设置了contract的id也就明确了像哪个购销合同中保存货物信息。
此时第二个input框的
value="${contract.id}意思就是将前台页面带过来的contract.id赋值给进入货物列表页面的模型驱动。让模型驱动带去action来保存。
合同商品新增的jsp中点击修改的超链接为:
<a href="contractProductAction_toupdate?id=${id}">修改</a>
以下是action中的save()
public String save(){ //获取合同商品明细的dao ContractProductDAO oDao = (ContractProductDAO) this.getDao("daoContractProduct"); //获取购销合同的dao ContractDAO cDao = (ContractDAO)this.getDao("daoContract"); //用加在超链接后面的参数去查购销合同对象 Contract contract = (Contract) cDao.get(Contract.class, model.getContract().getId()); //获得合同对象 //初始化 Arith arith = new Arith(); Double amount = 0.0; Double totalAmount = 0.0; if(model.getCnumber()!=null && model.getPrice()!=null){ if(contract.getTotalAmount()==null){ contract.setTotalAmount(new BigDecimal(0));//如果总金额为空,则初始化 } if(model.getCnumber()!=null && model.getPrice()!=null){ //计算金额 amount = arith.mul(model.getCnumber(), model.getPrice().doubleValue()); //金额=数量*单价 model.setAmount(new BigDecimal(amount)); //计算合同总金额= 所有货物金额的合计;技巧:旧的合同总额+新增货物的金额 totalAmount = arith.add(contract.getTotalAmount().doubleValue(), amount); } } if(!UtilFuns.isEmpty(model.getId())){ //修改 if(model.getCnumber()!=null && model.getPrice()!=null){ //查询当前是哪个货物,修改之前要先查询 ContractProduct contractProduct = (ContractProduct)oDao.get(ContractProduct.class, model.getId()); //修改时计算合同总金额= 旧的合同总额-修改前货物的金额+修改后货物的金额 totalAmount = arith.sub(totalAmount, contractProduct.getAmount().doubleValue()); } } contract.setTotalAmount(new BigDecimal(totalAmount)); //将所有货物的总金额保存进购销合同表 cDao.saveOrUpdate(contract); //将模型驱动中的单批货物的总金额(数量*单价)保存进货物表 oDao.saveOrUpdate(model); return tocreate(); }
下面做删除
首先在新增的jsp页面的列表后面增加一个删除的超链接:
<a href="contractProductAction_delete?id=${id}&contract.id=${contract.id}">删除</a>
这里解释一下为什么要带两个参数,首先第一个参数id就是货物的id,告诉action去查哪个货物然后把它删掉,第二个contract.id是因为,删除了货物,那么整个购销合同的金额就不对了,就需要重新计算,就需要用购销合同的id去查询到底是修改哪个购销合同中的金额。
下面截个图:
下面是action中的delete()
public String delete(){ /** * 前半部分操作为了修改金额 */ Arith arith = new Arith(); ContractProductDAO oDao = (ContractProductDAO) this.getDao("daoContractProduct");//获取货物表dao ContractProduct contractProduct = (ContractProduct)oDao.get(ContractProduct.class, model.getId()); //通过货物id查询出当前要删除的货物 ContractDAO cDao = (ContractDAO)this.getDao("daoContract");//获取购销合同dao Contract contract = (Contract) cDao.get(Contract.class, model.getContract().getId());//获得合同对象 //合同总额中减去删除这条记录的金额,第一个参数是原本合同里面的总金额,第二个参数是要删除的货物的金额 if(contractProduct.getAmount()==null){//老师这里少一次判断,如果要删除的货物的金额为空,则需要置0,不然报错! contractProduct.setAmount(new BigDecimal(0)); } Double totalAmount = arith.sub(contract.getTotalAmount().doubleValue(), contractProduct.getAmount().doubleValue()); //设置算出来的新的总金额 contract.setTotalAmount(new BigDecimal(totalAmount)); //保存进购销合同表 cDao.saveOrUpdate(contract); /** * 后半部分才是真正删除记录 */ //获取选中的所有的ID String[] ids = model.getId().split(", "); //分隔符 逗号空格 //这里是通过获取所有的id来批量删除货物记录 oDao.deleteAllById(ids, ContractProduct.class); return tocreate(); }
下面做附件
同样,在新增货物的列表增加附件列:
<a href="extCproductAction_tocreate?contractProduct.id=${id}&contractProduct.contract.id=${contract.id}">附件</a>
这里要带两个两个参数,第一个参数contractProduct.id是为了去附件表中查询这个货物所用有的全部附件,第二个参数contract有什么用呢?因为当你设置好附件之后你返回的是货物页面,那么你没有合同的id就没法去货物表中查询这个合同到底有哪些货物了。如果不带这个参数的话,点返回是会报错的。
下面是ExtCproductAction中的代码:
新增(包含查询附件的列表)
//转向新增页面 public String tocreate(){ //清除不需要回显的内容 model.setFactory(null); //准备下拉列表数据(所有生产厂家) FactoryDAO fDao = (FactoryDAO) this.getDao("daoFactory"); List<Factory> factoryList = fDao.find("from Factory o where o.state=1"); //1启用 ActionContext.getContext().put("factoryList", factoryList);//集合一般都放入map栈中,对象一般直接push ExtCproductDAO oDao = (ExtCproductDAO) this.getDao("daoExtCproduct"); //获得DAO对象 //某个货物下的所有附件 /** * 这里是查询附件表,列出这个货物的所有附件,所以要将货物表的id带过来 */ List<ExtCproduct> dataList = oDao.find("from ExtCproduct o where o.contractProduct.id='"+ model.getContractProduct().getId() +"'"); ActionContext.getContext().put("dataList", dataList);//集合一般都放入map栈中,对象一般直接push return "pcreate"; }
修改时,在jExtCproduct带过去的超链接:
<a href="extCproductAction_toupdate?id=${id}&contract.id=${contract.id}">修改</a>
同样需要将附件本身id和购销合同的id设置到模型驱动中去,因为修改附件就要修改附件表和购销合同表中的数据
由于附件的金额不用算,所以不用把货物的id带过去
下面是action中修改方法的代码:
public String toupdate(){ //准备下拉列表数据 FactoryDAO fDao = (FactoryDAO) this.getDao("daoFactory"); List<Factory> factoryList = fDao.find("from Factory o where o.state=1"); //1启用 ActionContext.getContext().put("factoryList", factoryList); //用带过来的附件id去附件表中查询这个附件的内容,单位是只还是套啊之类的 ExtCproductDAO oDao = (ExtCproductDAO)this.getDao("daoExtCproduct"); ExtCproduct obj = (ExtCproduct)oDao.get(ExtCproduct.class, model.getId()); //将查询到的附件对象压栈 ActionContext.getContext().getValueStack().push(obj); return "pupdate"; }
下面是删除的超链接:
<a href="extCproductAction_delete?id=${id}&contractProduct.contract.id=${contractProduct.contract.id}&contractProduct.id=${contractProduct.id}">删除</a>
这个超链接一共带了三个参数过去,第一个是本身附件表的主键,还有货物表的主键,还有合同表的主键,总结就是说,从表一定要携带所有祖先表的组件,才能一级一级返回去,不然就会查不到数据从而报错。写的时候注意根据模型驱动的结构来写,很容易写错,难点!
action中的删除代码很easy,和之前的没两样,就不贴了。最后贴一下最后那个附件删除的模型驱动结构。