程序员工作经验谈之商贸平台

程序员工作经验谈
1、怎样顺利找到工作,并稳稳当当坐下来呢?
①如何通过面试?
答:态度要积极,要听话、积极并且有热情。
表达能力要良好,能够流利介绍个人情况,例如工作情况,为何离职等。
专业基础要扎实,包括理论知识、J2EE基础知识并且能够熟练使用开发工具。
项目能力要展示出来,需要介绍项目背景,介绍核心业务模块及设计上的难点(特色、亮点)并且表述在项目中的工作职责及成就。
②如何通过试用期?
答:注重团队协作,要跟团队领导和同事打成一片。
快速适应岗位要求,要动手能力强,快速、高质量完成领导交给的任务,熟悉业务、编写文档,并且能够培训客户。
③如何升职加薪?
答:要能够独当一面,业务要精通,能够独立完成项目,技术难点要能够攻克或者能够当小组长带新人。

2、架构重要吗?
企业经过长年积累,都有资深的程序人员,都有成型的开发框架,这些框架基本在主流框架上做封装,我们开发人员第一要务就是在这些框架上来实现用户需求。所以,在学习框架的时候要学习其中的思想,从而能够举一反三,不要拘泥于任何具体的框架。

3、编码是程序员的所有工作吗?
初级程序员要求:业务(30%)、编码(25%)、沟通(20%)、设计(10%)、文档(10%)。
所谓的项目经验=业务+设计思路,所以程序员要认识到编码只是工作的一部分,要多熟悉业务,要注重设计并且加强沟通,提升自己写文档的能力。
02 学习项目预热阶段
1、如何学习此项目?
①通过此项目,熟悉项目开发流程。
成立项目组、分工合作、需求调研、设计、编码、交付客户、上线运行、维护。
②通过此项目,熟悉业务需求。
加深对物流行业、出口贸易、货运管理的业务理解。
③通过此项目,拓展设计思路。
考虑如何将用户的需求转化为数据库表和代码实现?
考虑如何优化设计,以最小的代价得到最高的运行和开发效率,同时业务逻辑清晰简洁。
综上:学习本项目,要主攻业务以及设计思路,而不是编码。

2、分组开发此项目(如下图)

3、项目的开发架构(减少关注点)

4、项目开发环境

5、课程安排(模拟软件企业开发环境,分组开发)

6、项目要求
要把握三图:用例图、结构图、模型图
要把握三句:背景、业务、亮点
要把握三块:合同、打印、报表
03 熟悉项目背景和项目需求
1、项目背景
①杰信商贸是物流行业一家专门从事进出口玻璃器皿贸易的公司。公司总部位于十一个朝代的帝王之都西安,业务遍及欧美。随着公司不断发展壮大,旧的信息系统已无法满足公司的快速发展需求,妨碍公司成长,在此背景下,公司领导决定研发《杰信商贸综合管理平台》。
②《杰信商贸综合管理平台》分三期完成。一期完成仓储管理(包括:采购单、仓库、货物、条形码、入库、出库、退货、盘点、库存、库存上限报警、统计查询)和展会管理(包括:展会管理、出单管理),形成货物统一数字化管理。二期完成货运全流程管理,包括购销合同、出货表统计、出口报运、HOME装箱单、装箱单、委托单、发票、财务统计等。三期完成决策分析(包括:成本分析图、销售情况统计、重点客户、经营情况同期比对统计、工作绩效),为公司经营决策提供数据支持。
附:HOME装箱单是给客户看的单子,相当于预装箱单。
③系统上线后,解决了客户的实际问题,促进了公司的发展,得到公司认可和赞誉。
【仓储子系统】:实现仓储的信息化管理,公司管理层随时了解进货、出货、损耗及库存情况,为公司精细化管理,0库存的经营目标奠定了扎实的基础。
【展会子系统】:在展会上快速打印出客户关心的产品,为客户节约了宝贵的时间,赢得客户的认可,促进了销售人员现场签单的几率。当其它公司还在手工画图,我们已经将精美的文件递到了客户手中。
【货运子系统】:使业务流程更加顺畅,信息传递更加迅速,提高了办理效率,提高了分散全球各地部门协作能力。充分利用计算机的快速计算,将客户从日常琐事解放出来,可以将更多精力投入到公司经营上。用户相当满意,给予很高评价。

2、项目需求
①用例图

②系统功能结构图

04 了解系统特色(面试重点)
1、系统升级改造,由struts1.1升级为struts2.3(整合)
按领导要求,对本项目进行升级改造。将struts1升级为struts2,工作量巨大,3个人修改了半个月,并经过大量测试。struts1和struts2不能完全共存,不能简单的映射.do到上struts2。Action层几乎颠覆性的进行改造。由于jsp中未使用struts1的标签,这部分不需要大改。经过改造,减少了大量的struts-config-模块.xml配置文件,减少了大量的action,action内方法调用更加简洁。但由于本系统访问人数在百人内,也没有集中的业务访问,因此性能提升不明显。

2、流程控制,合同、报运、装箱、委托、发票、财务
简洁的流程控制设计,实现流程的流转,同时可以实现流程的退回。例如:报运模块。录入时状态为“草稿”,此时下一个流程“装箱”将无法看到新录入的信息,当录入者确定录入的报运信息无误时,点击“保存”,状态变为“已上报”,此时负责装箱单处理的专责才可以看到其信息。其选择多个报运,进行【装箱】。保存后状态变为“装箱”,委托专责才可以看到装箱信息,进行【委托】,保存后状态变为“委托“,发票专责才可以看到装箱和委托信息,进行【发票】,保存后状态变为”发票,财务专责才可以看到装箱、委托和发票信息,进行【财务】,保存后状态变为“财务”。此时合同管理员才可以进行归档,进行【归档】,流程完成,信息变为历史信息,只能在历史信息中进行检索。这样减少当前信息检索的数据,加快信息的查询和显示。

3、信息复制,合同、货物、附件信息快速复制
系统实现信息快速复制功能,充分方便使用者。例如:通常建立购销合同后,合同中会包含数十个货物,每个货物有多个附件。这样一个购销合同包括合同下的货物和附件的信息近百项。有时客户在录入新合同时,信息会基本和某个旧合同非常近似。如果手工录入,录入量非常繁重,同时很低效。而系统实现点击【复制】功能,自动复制合同的信息,合同下货物信息,对应货物下的附件信息。原来数10分钟完成的事情,半秒中就完成。用户只需在复制的合同上修改相应信息,使用起来方便许多。系统上线后,此功能深受客户欢迎。

4、模板打印,基于excel模板的打印,poi的全面应用
实现用户复杂业务单据的打印,利用第三方工具poi实现数据输出到excel中,并在线下载打印。包括按用户模板打印,包括数据的自动计算。例如购销合同的分页打印,报运单自动计算分工作簿打印,出货月统计表的页眉自动设置,财务报表的自动小计、合计功能,同时系统还实现了根据单元格内容,自动调整其单元格高度。由于使用excel,用户无需安装第三方打印插件。同时系统支持excel2003、excel2007、excel2010多个版本。同时,无需花钱购买第三方报表工具,为客户节约了系统资金上的投入。系统上线后,打印出彩色单据,非常漂亮,在展会上给国外客户看,老外很新奇,吸引不少订单。并且数据统计分毫不差,用户非常满意。

5、防止文件打印并发,基于windows文件处理机制
系统为多部门人员互联网上使用,难免出现并发情况,在架构设计上,充分考虑到这种情况。例如当两个用户打印同一个购销合同时,系统会判断是否临时目录中是否有打印文件存在,有则换名称,再次判断,直到不存在时,才会执行打印。这样充分防止多用户并发访问下的打印。同时,为防止临时目录下文件过多,难以维护,自动按打印时的日期分成多个目录。

6、统一查询,清空机制
实现字符串字段简单配置即可实现灵活组合的类似google搜索条的模糊多条件查询效果。同时在页面中实现统一的查询条。利用js对查询条数据快速清空,由于利用js,进行本地操作,快速,不耗费服务器资源。此功能大大提高了查询功能开发的效率,复制代码,简单配置即可。

7、统一数据字典,一张表,树形n级分类支持【难点】
传统数据字典设计为两张表,一个分类、一个内容。维护时也不方便。两张表分别维护。本系统采用一张表设计,使数据字典维护非常便捷。同时支持n级树形结构,支持内容的排序。同时树支持截断树,这样方便权限控制。

8、用户个性化配置,用户根据自己的需要可以动态定制自己的信息
用户录入数据时,很多内容都相同,特别很多大段的文字内容,数百字,如果每次都录入,既耗时,也耗力。系统支持用户将常录入的信息可以用户自行配置,这样在新建页面时,系统自动填充这些内容,用户只需修改。减少了用户的录入。同时当信息发生变化时,用户只需自行修改,就适应了新的变化。不仅加快了信息录入的速度和录入的准确率,减少了错误,还有很好的适应性,快速适应用户需求的变化。而且根据每个操作用户的不同,他们都可以自行配置。

9、数据挖掘,业务增值,挖掘基础数据的价值,为高层提高决策数据
充分利用用户的基础数据,深挖用户潜在需求和充分发挥数据的价值。例如合同数据。合同中有客户信息,有货物信息,有附件信息,有货物的生产厂家信息。从合同的签订日期,我们实现公司一年签单气泡图,从中直观的看到企业签单旺季和淡季。从货物信息,我们实现按月、季度、年度统计公司最受欢迎产品和最不受欢迎的产品,同时进行近3年产品受欢迎趋势图。从货物销售的客户中分析全球货物销售比例饼图。从生产厂家分析出公司合作的厂家生产比例图。这些数据的深度分析结果为公司的经营提供了直接的一手的决策信息支持。此功能客户公司高层给予高度肯定。
05 系统搭建(非Maven搭建)
1、新建web project,发布到ROOT下(项目为UTF-8编码)

修改JSP编码为UTF-8。

2、引入jar包
①拷贝{资料/4-jar包/ALL所有包}下内容到工程的lib目录中,所有jar包包含:
Hibernate 3.5.6
Spring 3.0.2
Struts 2.3
数据库驱动 mysql 5.0.87
基础包 junit,poi,log4j,c3p0
②配置jre环境,选择jdk1.6,选择用1.6编译

3、拷贝工具类、拷贝界面原型
拷贝{代码/02-工具类/cn}下内容到工程的src下
拷贝{资料/3-界面原型/ROOT}下内容到工程的WebRoot下

附:目录结构

4、配置文件 hibernate.cfg.xml ,beans.xml ,struts.xml ,web.xml
查看{资料/4-查看配置文件}中的文件,拷贝这些文件然后进行修改。
注:
找工作过程中如果碰到了机试,那么最好带上U盘,提前准备好jar包以及配置文件。
hibernate.cfg.xml

<?xml version="1.0" encoding= "UTF-8"?> com.mysql.jdbc.Driver jdbc:mysql://localhost:3306/ jkdb?characterEncoding=UTF-8 root root
         <!-- 基础配置 -->
         <property name="hibernate.dialect" >org.hibernate.dialect.MySQL5Dialect</ property>
         <!-- 下面这段配置,只有在练习的时候才会配置,真正上线之后是不会配置的 -->
         <!--property name="hibernate.hbm2ddl.auto">update</property -->
         <property name="hibernate.connection.autocommit" >true</ property>
         <!-- property name="hibernate.format_sql">true</property -->
         <property name="show-sql" >true</ property>
  
         <!-- 加载映射文件 -->

   </session-factory>

beans.xml

<?xml version="1.0" encoding= "UTF-8"?>

   <!-- 1:创建SessionFactory对象,这是spring整合Hibernate的核心 -->
   <bean id= "sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" >
         <property name="configLocation" >
               <value> classpath:hibernate.cfg.xml</value >
         </property>
   </bean>
  
   <!-- 2:加载DAO对象 -->
   <bean id= "daoRoot" class ="cn.itcast.entity.dao._RootDAO" autowire="byName" />" />

struts.xml

<?xml version="1.0" encoding= "UTF-8"?>
   <include file="struts2/struts-test.xml" />

web.xml

<?xml version="1.0" encoding= "UTF-8"?>

   <!-- 当web容器启动的时候,加载spring容器(beans.xml) -->
   <context-param>
         <param-name> contextConfigLocation</param-name >
         <param-value> classpath:beans.xml</param-value >
   </context-param>
   <listener>
         <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class>
   </listener>


   <!-- 配置struts2的过滤器,这是struts2运行的核心 -->
   <filter>
         <filter-name> struts2</filter-name >
         <filter-class> org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter </filter-class>
   </filter>
   <filter-mapping>
         <filter-name> struts2</filter-name >
         <url-pattern> /*</ url-pattern>
   </filter-mapping>
index.jsp

5、建立数据库&测试表
建立数据库,编码格式为uft8
CREATE DATABASE IF NOT EXISTS itcastjkdb DEFAULT CHARSET utf8 COLLATE utf8_general_ci;

6、发布、测试(没有报错,说明系统搭建成功)

附:
将他人的项目导入MyEclipse的时候,可能由于某些原因会莫名奇怪的报错,并且找不到原因。这时候可以点击Project–>Clean,进行重新编译。但是重新进行编译,MyEclipse会做语法校验,比如xml、js等校验,会影响编译进度,因此最好将校验关闭掉。

但也可以单独对某个文件或者文件夹进行Validation操作。

06 系统代码
1、业务逻辑
数据字典是系统的基础,其作用是减少重复信息,保证数据的唯一性。
本系统包括人员级别、厂家类型、附件类型、货物类型等。用户可以自行扩充,提高系统的灵活性和程序的扩展性。

2、拿到问题,怎么样去做?
①分析
②设计(转换成数据库表、业务控制)、可行性分析
③编码

3、功能描述及其分析

4、数据库设计,执行SQL,创建数据库表

附:
1、数据库表主键用什么类型?
int long 处理速度快
varchar(uuid) 使用uuid,可以在项目整合的时候,防止主键冲突
2、建立数据库表的时候创建外键否?
测试、调试阶段:不需要创建外键关系,使用代码来维护。
系统上线稳定维护阶段:创建外键。防止用户不小心改动数据造成外键关系错误。

5、创建映射文件ClassCode.hbm.xml、TextCode.hbm.xml
ClassCode.hbm.xml

<?xml version="1.0" encoding= "UTF-8"?>

TextCode.hbm.xml

<?xml version="1.0" encoding= "UTF-8"?>

6、创建PO文件ClassCode.java、TextCode.java
ClassCode.java
public class ClassCode{
public Set getTextCodes() {
return textCodes ;
}
public void setTextCodes (Set textCodes) {
this.textCodes = textCodes;
}
private Set textCodes ;
private String id ;
private String name ;
public String getId() {
return id ;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name ;
}
public void setName(String name) {
this.name = name;
}
}

TextCode.java
public class TextCode {
private ClassCode classCode ;
public ClassCode getClassCode() {
return classCode ;
}
public void setClassCode(ClassCode classCode) {
this.classCode = classCode;
}
private String id ;
private String name ;
public String getId() {
return id ;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name ;
}
public void setName(String name) {
this.name = name;
}
}

7、创建dao
TextCodeDAO.java
public class TextCodeDAO extends _RootDAO {

}

ClassCodeDAO.java
public class ClassCodeDAO extends _RootDAO {

}

8、声明
hibernate.cfg.xml

beans.xml

< bean id = “daoClassCode” class = “cn.itcast.entity.dao.ClassCodeDAO” autowire = “byName”/>
< bean id = “daoTextCode” class = “cn.itcast.entity.dao.TextCodeDAO” autowire = “byName”/>

9、创建action:列表(方法命名规则:to+动作;转向页面命名规则:p+动作)
TextCodeAction.java
public class TextCodeAction extends _BaseStruts2Action implements ModelDriven {
private TextCode model = new TextCode();
public TextCode getModel() {
return model ;
}

   //列表
   public String list(){
        TextCodeDAO oDao = (TextCodeDAO) this.getDao("daoTextCode" );
        List<TextCode> dataList = oDao.find("from TextCode o");
        ActionContext. getContext().put("dataList", dataList);
        
        return "plist" ;
  }
  
   //转向新增页面
   public String tocreate(){
         //准备数据 获取代码分类 下拉表
        TextCodeDAO oDao = (TextCodeDAO) this.getDao("daoTextCode" );
        List<ClassCode> classCodeList = oDao.find("from ClassCode o");
        ActionContext. getContext().put("classCodeList", classCodeList);
        
        return "pcreate" ;
  }
  
   //保存
   public String save(){
        TextCodeDAO oDao = (TextCodeDAO) this.getDao("daoTextCode" );
        oDao.saveOrUpdate( model);
        
        return list();
  }
  
   //转向修改页面
   public String toupdate(){
         //准备数据 获取代码分类 下拉表
        TextCodeDAO oDao = (TextCodeDAO) this.getDao("daoTextCode" );
        List<ClassCode> classCodeList = oDao.find("from ClassCode o");
        ActionContext. getContext().put("classCodeList", classCodeList);
        
        TextCode obj = (TextCode) oDao.get(TextCode. class, model .getId());
        ActionContext. getContext().getValueStack().push(obj);
        
        return "pupdate" ;
  }
  
   //删除
   public String deleteone(){
        TextCodeDAO oDao = (TextCodeDAO) this.getDao("daoTextCode" );
        oDao.delete( model.getId(), TextCode.class);
        
        return list();
  }
  
   //批量删除
   public String delete(){
        String[] ids = model.getId().split(", " );       //注意分隔符
        TextCodeDAO oDao = (TextCodeDAO) this.getDao("daoTextCode" );
        oDao.deleteAllById(ids, TextCode. class);

        return list();
  }
  
   //转向查看页面
   public String toview(){
         //准备数据
        TextCodeDAO oDao = (TextCodeDAO) this.getDao("daoTextCode" );
        TextCode obj = (TextCode) oDao.get(TextCode. class, model .getId());
        ActionContext. getContext().getValueStack().push(obj);
        
        return "pview" ;
  }     

}

ClassCodeAction.java
public class ClassCodeAction extends _BaseStruts2Action implements ModelDriven {
private ClassCode model = new ClassCode();
public ClassCode getModel() {
return model ;
}

   //列表
   public String list(){
        ClassCodeDAO oDao = (ClassCodeDAO) this.getDao("daoClassCode" );
        List<ClassCode> dataList = oDao.find("from ClassCode o");
        ActionContext. getContext().put("dataList", dataList);
        
        return "plist" ;
  }
  
   //转向新增页面
   public String tocreate(){
        
         return "pcreate" ;
  }
  
   //保存
   public String save(){
        ClassCodeDAO oDao = (ClassCodeDAO) this.getDao("daoClassCode" );
        oDao.saveOrUpdate( model);
        
        return list();
  }
  
   //转向修改页面
   public String toupdate(){
         //准备数据
        ClassCodeDAO oDao = (ClassCodeDAO) this.getDao("daoClassCode" );
        ClassCode obj = (ClassCode) oDao.get(ClassCode. class, model.getId());
        ActionContext. getContext().getValueStack().push(obj);
        
        return "pupdate" ;
  }
  
   //删除
   public String delete(){
        ClassCodeDAO oDao = (ClassCodeDAO) this.getDao("daoClassCode" );
        oDao.delete( model.getId(), ClassCode.class);
        
        return list();
  }

}

附:
1、为什么保存、修改后不返回list页面而返回的是action的list方法?
答:为了准备列表的数据。可以直接返回页面,那样列表页面就没有数据可供显示。
2、上面的getDao方法继承自_BaseStruts2Action.java,目的就是获取DAO对象。
public Object getDao(String dao){
return AppContext.getInstance().getAppContext().getBean(dao); //获取DAO对象
}

注:
如果对action进行拦截控制,那最好不直接调用,因为内部调用,拦截器无法发挥作用。

10、创建jsp页面WebRoot/baseinfo/classcode/jClassCodeList.jsp、jClassCodeUpdate.jsp、jClassCodeCreate.jsp(全码见源代码,这里只列出重点代码)
拷贝“资料\3-界面原型\JSP文件模板”下的模板文件,此模板通常由美工提供,主要是定系统的样式。

修改模板文件,加入业务内容:
jClassCodeList.jsp
<s:iterator value=“#dataList” var=“dl”>

< input type ="radio" name="id" value="${id} "/> ${id} ${name}

jClassCodeUpdate.jsp
< input type =“hidden” name =“id” value ="${id} ">
action保存时就靠它来区分是新增还是修改。

附:
1、为何新建、修改时转向的是action的tocreate、toupdate方法,而不直接转向页面呢?

  • 新建
  • 修改
  • 答:为了准备数据,就是在为新建页面上的下拉框准备数据。 注: 上面的formSubmit方法是从common.js中引入的,目的是为页面中的第一个表单属性赋值。

    2、将信息放在request中,页面该如何获取呢?
    ClassCodeAction.java
    public String list(){
    List < ClassCode> dataList = oDao.find(“from ClassCode”);
    HttpServletRequest request = ServletActionContext.getRequest();
    request.setAttribute(“dataList”, dataList);

      return " plist";
    

    }
    jClassCodeList.jsp
    <s:iterator value=“#request.dataList” var=“dl”>

    修改left.jsp添加访问入口:
    < a href = “/baseinfo/classCodeAction_list” target = “main” id = “aa_1” onclick = “linkHighlighted(this)” >代码分类 </ a>

    11、创建struts-baseinfo.xml

    <?xml version="1.0" encoding= "UTF-8"?> /baseinfo/classcode/jClassCodeList.jsp /baseinfo/classcode/jClassCodeCreate.jsp /baseinfo/classcode/jClassCodeUpdate.jsp /baseinfo/textcode/jTextCodeView.jsp /baseinfo/textcode/jTextCodeList.jsp /baseinfo/textcode/jTextCodeCreate.jsp /baseinfo/textcode/jTextCodeUpdate.jsp 在struts.xml中增加< include file ="struts2/struts-baseinfo.xml" />。

    12、测试系统
    向数据库中插入两条数据,然后登录系统进行测试。

    测试列表显示

    测试新增

    测试修改

    测试删除

    13、实现textCode:复制action,复制页面
    替换ClassCode相关的Action与页面中信息为TextCode的信息

    添加分类列表
    TextCodeAction中实现tocreate方法,为分类准备数据。
    TextCodeAction.java
    //转向新增页面
    public String tocreate(){
    //准备数据 获取代码分类 下拉表
    TextCodeDAO oDao = (TextCodeDAO) this .getDao(“daoTextCode” );
    List classCodeList = oDao.find( “from ClassCode o”);
    ActionContext. getContext().put( “classCodeList”, classCodeList);

      return "pcreate" ;
    

    }

    修改create页面

    分类:

    测试新增分类下拉列表

    附:
    由于修改页面中也需要分类下拉列表,因此做与上面相似的操作,此处略。

    增加查看功能
    TextCodeAction中实现toview方法。
    TextCodeAction.java
    public String toview(){
    //准备数据
    TextCodeDAO oDao = (TextCodeDAO) this.getDao(“daoTextCode” );
    TextCode obj = (TextCode) oDao.get(TextCode. class, model.getId());
    ActionContext.getContext().getValueStack().push(obj);

      return "pview" ;
    

    }

    加查看按钮 jTextCodeList.jsp

  • < a href= "#" οnclick= "formSubmit('/baseinfo/textCodeAction_toview','_self');this.blur();" >查看< /a>< /li>
  • 新建jTextCodeView.jsp查看页面

  • < a href= "#" οnclick= "history.go(-1);this.blur();" >返回< /a>< /li> 注: 如果用浏览器的“回退”按钮返回,那么如果其他用户对数据库进行了更新,则不会显示出来。
  • 修改view页面

    分类 $ {classCode.name}

    测试查看

    注:
    通过在列表记录上增加快捷链接

    ${classCode.name } 就可以实现通过直接点击分类名就可以查看本条记录的详细信息。

    实现批量删除
    TextCodeAction中实现delete方法。
    TextCodeAction.java
    //批量删除
    public String delete(){
    //注意分隔符,struts2中,如果页面上有多个元素id相同,那么它们提交后,值就会以“, ”组织起来存入model中。
    String[] ids = model .getId().split( ", " );
    TextCodeDAO oDao = (TextCodeDAO) this .getDao(“daoTextCode” );
    oDao.deleteAllById(ids, TextCode. class );

      return list();
    

    }

    测试批量删除

    附:
    什么时候使用Serializable?
    ①复合主键
    ②文件上传下载

    注:
    如果使用EditPlus直接修改JSP,MyEclipse中的项目文件夹一定要刷新一次,否则Tomcat无法部署修改过的JSP。
    07 厂家信息
    1、业务逻辑
    基础模块:维护常用信息,目的也是减少信息重复,保证信息的一致性。和数据字典的区别是,数据字典结构简单,一般为编号+内容,常用于下拉框。而基础信息较复杂,多个业务字段。常用于业务中管理信息。
    厂家信息:管理与公司合作的生产厂家,包括厂家名称、联系人、地址、电话等信息。用在购销合同中货物、附件可选择对应的厂家。

    2、功能描述及其分析

    3、技术要点

    4、数据库设计,执行SQL,创建数据库表

    5、创建PO文件
    public class Factory {
    private String id ;
    private String ctype ;
    private String typeName ;
    private String fullName ;
    private String factoryName ;
    private String contractor ;
    private String phone ;
    private String mobile ;
    private String fax ;
    private String cnote ;
    private String inspector ;
    private String state ;
    //成员变量不要用int类型,采用包装类
    private Integer orderNo ;
    private String createBy ;
    private String createDept ;
    private Date createTime ;
    …//get、set方法
    }

    6、创建映射文件Factory.hbm.xml

    <?xml version="1.0" encoding= "UTF-8"?>
             <property name="fullName" column="FULL_NAME" type="string" />
             <property name="factoryName" column="FACTORY_NAME" type="string" />
             <property name="contractor" column="CONTRACTOR" type="string" />
             <property name="phone" column="PHONE" type="string" />
             <property name="mobile" column="MOBILE" type="string" />
             <property name="fax" column="FAX" type="string" />
             <property name="cnote" column="CNOTE" type="string" />
             <property name="inspector" column="INSPECTOR" type="string" />
             <property name="state" column="STATE" type="string" />
             <property name="orderNo" column="ORDER_NO" type="integer" />
            
             <property name="createBy" column="CREATE_BY" type="string" />
             <property name="createDept" column="CREATE_DEPT" type="string" />
             <property name="createTime" column="CREATE_TIME" type="timestamp" />
       </class>
    
    注: Date类型的成员变量在映射文件中使用timestamp,一方面,是为了适应不同类型的数据库。另一方面,所有涉及日期的字段一定要有年月日、时分秒,这样才能够应对客户不断变化的需求。

    附:
    ①在list页面要显示分类的名称,但又没有配置对象关系,那如果做呢?
    Factory.hbm.xml中定义虚拟列typeName;PO对象中生成GET、SET方法

    List.jsp

    ${typeName} ②应用formula,注意其SQL的特殊写法。 返回单值 设定别名 Where字段为数据库字段,不是映射字段。大小写没关系。

    7、创建FactoryDAO.java
    public class FactoryDAO extends _RootDAO {

    }

    8、声明hbm和dao
    hibernate.xml
    < mapping resource =“cn/itcast/entity/Factory.hbm.xml” />

    beans.xml
    < bean id =“daoFactory” class =“cn.itcast.entity.dao.FactoryDAO” autowire =“byName”/>

    9、建立FactoryAction.java,复制textCodeAction进行修改
    public class FactoryAction extends _BaseStruts2Action implements ModelDriven {
    private Factory model = new Factory();
    public Factory getModel() {
    return model ;
    }

       //列表
       public String list(){
            FactoryDAO oDao = (FactoryDAO) this.getDao("daoFactory" );
            List<Factory> dataList = oDao.find("from Factory o");
            ActionContext. getContext().put("dataList", dataList);
            
            return "plist" ;
      }
      
       //转向新增页面
       public String tocreate(){
            //准备数据
            FactoryDAO oDao = (FactoryDAO) this.getDao("daoFactory" );
            List<TextCode> textCodeList = oDao.find("from TextCode o where o.classCode.id='0103'");             
            //0103 厂家分类
            ActionContext. getContext().put("textCodeList", textCodeList);
            
            return "pcreate" ;
      }
      
       //保存
       public String save(){
            FactoryDAO oDao = (FactoryDAO) this.getDao("daoFactory" );
            Factory f = null;
             //初始化
             if(model .getId()==null){
                  f = new Factory();
                  f.setState( "1");        //1正常0停用
            } else{
                  f = (Factory) oDao.get(Factory. class, model .getId());
            }
            f.setCtype( model.getCtype());
            f.setFullName( model.getFullName());
            f.setFactoryName( model.getFactoryName());
            f.setContractor( model.getContractor());
            f.setPhone( model.getPhone());
            f.setMobile( model.getMobile());
            f.setFax( model.getFax());
            f.setCnote( model.getCnote());
            f.setInspector( model.getInspector());
            f.setOrderNo( model.getOrderNo());
            
            oDao.saveOrUpdate(f);
            
            return list();
      }
      
       //转向修改页面
       public String toupdate(){
             //准备数据
            FactoryDAO oDao = (FactoryDAO) this.getDao("daoFactory" );
            List<TextCode> textCodeList = oDao.find("from TextCode o where o.classCode.id='0103'");             //0103 厂家分类
            ActionContext. getContext().put("textCodeList", textCodeList);
            
            Factory obj = (Factory) oDao.get(Factory. class, model.getId());
            ActionContext. getContext().getValueStack().push(obj);
            
            return "pupdate" ;
      }
      
       //转向查看页面
       public String toview(){
             //准备数据
            FactoryDAO oDao = (FactoryDAO) this.getDao("daoFactory" );
            Factory obj = (Factory) oDao.get(Factory. class, model.getId());
            ActionContext. getContext().getValueStack().push(obj);
            
            return "pview" ;
      }     
      
       //批量删除
       public String delete(){
            String[] ids = model.getId().split(", " );       //注意分隔符
            FactoryDAO oDao = (FactoryDAO) this.getDao("daoFactory" );
            oDao.deleteAllById(ids, Factory. class);
            
            return list();
      }
      
       //启用
       public String start(){
             this.chstate("1" );
             return list();
      }
      
       //停用
       public String stop(){
             this.chstate("0" );
             return list();
      }
      
       //修改状态 1正常0停用
       private void chstate(String value){
            String[] ids = model.getId().split(", " );       //注意分隔符
            Factory f = null;
             Set oSet = new HashSet();
            FactoryDAO oDao = (FactoryDAO) this.getDao("daoFactory" );
             for(int i=0;i<ids.length;i++){
                  f = (Factory) oDao.get(Factory. class, ids[i]);
                  f.setState(value);
                  
                  oSet.add(f);
            }
            oDao.saveOrUpdateAll(oSet);                //批量保存
      }
    

    }

    10、struts配置
    struts-basicinfo.xml

    <?xml version="1.0" encoding= "UTF-8"?> /basicinfo/factory/jFactoryView.jsp /basicinfo/factory/jFactoryList.jsp /basicinfo/factory/jFactoryCreate.jsp /basicinfo/factory/jFactoryUpdate.jsp struts.xml < include file ="struts2/struts-basicinfo.xml" />

    11、列表功能:jsp页面(创建jFactoryList.jsp、jFacotryCreate.jsp、jFactoryUpdate.jsp、jFactoryView.jsp)(全码见源文件,这里仅列出重要部分代码)
    jFactoryList.jsp
    多选按钮:支持批量选择和批量反选

    加行号:
    <s:iterator value=“#dataList” var=“cp” status=“line” >
    <s:property value=“#line.index+1” />

    访问入口:baseinfo/left.jsp
    < li> 厂家信息

    12、新增功能
    为下拉框准备测试数据,初始化测试数据
    DELETE FROM class_code_c;
    INSERT INTO class_code_c (CLASS_CODE_ID, NAME) VALUES(‘0103’,‘厂家分类’);
    INSERT INTO class_code_c (CLASS_CODE_ID, NAME) VALUES(‘402880e73f08539f013f085543b60002’,‘附件分类’);
    INSERT INTO class_code_c (CLASS_CODE_ID, NAME) VALUES(‘402880e73f08539f013f08558b8d0004’,‘用户级别’);

    创建基础数据sys_code_b,执行“资料\2-数据库\1-初始化脚本.sql”

    如何从已有表中查出数据插入到另一个结构类似的表中?
    INSERT INTO TEXT_CODE_C
    SELECT sys_code_id,‘0103’ AS CLASS_CODE_ID,NAME FROM sys_code_b WHERE parent_id=‘0103’

    为新增、修改页面准备下拉框数据,ACTION 中tocreate()、toupdate()方法
    HQL: from TextCode t where t.classCode.id='0103’
    List ctypeList = oDao.find(“from SysCode t where t.classCode.id=‘0103’”);
    ActionContext.getContext().put(“ctypeList”, ctypeList);

    厂家类型下拉框
    <s:select list=“ctypeList” name=“ctype”
    listKey=“id” listValue= “name”
    headerKey=“” headerValue= “–请选择–” >
    </s:select>

    测试保存

    13、修改功能
    //保存
    public String save(){
    FactoryDAO oDao = (FactoryDAO) this.getDao(“daoFactory”);
    if(model.getId()==null){
    model.setState(“1”); //1正常0停用
    }
    oDao.saveOrUpdate(model);

     return list();
    

    }
    如果使用上面的代码,修改时,将会导致state由于页面没有,而被置null。这不是我们要的结果,如何修改呢?
    1、update jsp页面增加隐藏域
    2、不能直接使用model方法,而new新对象,get方法得到,然后set
    //保存
    public String save(){
    FactoryDAO oDao = (FactoryDAO) this.getDao(“daoFactory” );
    Factory f = null;
    //初始化
    if(model .getId()==null){
    f = new Factory();
    f.setState( “1”); //1正常0停用
    } else{
    f = (Factory) oDao.get(Factory. class, model .getId());
    }
    f.setCtype( model.getCtype());
    f.setFullName( model.getFullName());
    f.setFactoryName( model.getFactoryName());
    f.setContractor( model.getContractor());
    f.setPhone( model.getPhone());
    f.setMobile( model.getMobile());
    f.setFax( model.getFax());
    f.setCnote( model.getCnote());
    f.setInspector( model.getInspector());
    f.setOrderNo( model.getOrderNo());

      oDao.saveOrUpdate(f);
     
      return list();
    

    }

    测试修改

    14、批量删除功能:如何批量删除?
    JSP页面设置chekbox多选框
    ①checkbox框的特性是,只有选中的才会提交到后台也就是action中
    ②如果多个同名,则后台需要按数组方式处理 request.getParameterVales()

    修改action的delete方法
    public String delete(){
    String[] ids = model.getId().replaceAll(" “, “”).split(”,");
    FactoryDAO oDao = (FactoryDAO) this.getDao(“daoFactory”);
    oDao.deleteAllById( ids, Factory.class);

      return list();
    

    }

    测试批量删除

    15、启用和停止功能:如何实现启用和停止操作,并进行批量操作?
    FactoryAction.java
    public String begin(){
    this.state(“1”);
    return list();
    }

    public String stop(){
    this.state(“0”);
    return list();
    }

    private void state(String curValue){
    String[] ids = model.getId().replace(" “, “”).split(”,");
    FactoryDAO oDao = (FactoryDAO) this.getDao(“daoFactory”);
    Factory obj;

     Set oSet = new HashSet();
     for(int i=0;i<ids.length ;i++){
          obj  = (Factory) oDao.get( Factory.class, ids[i]);
          obj.setState(curValue);
          oSet.add(obj);
     }
     oDao.saveOrUpdateAll(oSet);
    

    }

    列表页面状态显示转换:
    <s:if test=“state0" >停止</ s:if>
    <s:elseif test="state
    1” > 启用</ font></s:elseif >

    启用和停止功能:页面按钮
    List页面加“启用”和“停用”按钮

  • 启用
  • 停止
  • 执行sql中的脚本:
    资料\2-数据库\1-初始化厂家信息脚本.sql

    测试启用和停用功能

    如果想要实现直接点击“启用”就可以变为“停用”,或者反之。则为其加上超链接即可。
    <s:if test=“state1" > 启用</s:if>
    <s:if test="state
    0” >< font color=‘red’ >停用</ font></s:if></ td>

    08 购销合同之合同部分功能实现
    1、业务逻辑
    客户签单后,公司向厂家下达购销合同,包括货物的具体要求和交期。合同按不同厂家打印购销合同单,货物、附件各自打印,由公司驻当地销售人员分发到各工厂。
    注:
    购销合同是跟生产厂家签订的合同,而不是与客户签订的合同。

    2、功能描述及其分析

    3、技术要点

    4、购销合同模板

    附:
    ①一个客人订购的商品可能需要由不同的厂家生产,因此一个客户的单子可能对应多个购销合同。
    ②购销合同中收购方是固定的,就是杰信公司。但是数据库中设置了相关的字段,是考虑到将来的发展。例如,杰信以后可能会有子公司,那么这个字段就不是固定的了。
    ③购销合同中的合同号格式为:年份+JK+3位随机号(杰信一年购销合同单子的数量达不到100个)。
    ④同一个厂家的货物放在同一页(一页最多放两个货物),不同厂家的放在不同页。

    出货表

    出货表就是对购销合同的月统计。出货表与购销合同表都是由公司里同一个人录入的。
    附:
    ①出货表中的订单号就是购销合同中的合同号,只是名字不同而已。
    ②出货表中的船期是由后期船务人员录入的,所以船务既负责装箱,也负责报运。

    5、数据库设计,执行SQL,创建数据库表

    由上图可见,购销合同与合同商品明细是一对多的关系,合同商品明细与合同商品附件是一对多的关系。
    附:
    设计表结构的时候,厂家不应该跟合同绑定,而需要跟货物绑定。根据客户订购的货物,从而决定向哪些厂家下购销合同单。

    购销合同字段

    附:
    字段设计说明:
    ①购销合同表中的字段在购销合同报表中都能找到对应的内容,但是某些字段在购销合同报表中找不到对应的内容,例如:客户名称(出货表)、船期、贸易条款。但是,这些字段在出货表中都可以找到对应的内容。并且因为出货表和购销合同都是由同一个人操作,所以这些字段放在同一个表中。
    ②购销合同表中的字段“重要程度”对应的是购销合同报表中的货物描述旁的★个数。
    ③购销合同表中的字段“打印版式”(一个页面可以打印两件货,也可以是一件货,这个由客户来确定),页面上可以做一个供用户选择的下拉框来实现此功能。之所以将其放入表字段中,是因为考虑到用户可能过了很久之后又要重新打一份购销合同单,但是忘记这个单子以前是按照一页两个货物还是一页一个货物打印了。
    ④人名字段长度一般都是20或者30。

    合同商品明细字段

    附:
    字段设计说明:
    ①一般,图片不会直接存入数据库。因为这样的话,数据库的优化就不是很好做了。一般都是将图片存放在服务器上,然后将图片路径存入数据库中。
    ②包装单位只有两种:“只”或者“套”。
    ③表中的“厂家”字段中存放的内容是关联到生产厂家表的外键值。
    ④表中毛重、净重以及长宽高等字段是报运的时候需要用到的。
    ⑤主表(购销合同表)中有权限控制字段(CREATE_BY、CREATE_DEPT、CREATE_TIME),子表(合同商品明细表)中没有权限控制字段,这是因为主表中的权限已经能够控制用户是否能够访问到子表中的数据了,所以子表就不需要有了。但是,单表肯定需要权限控制字段。

    合同商品附件字段

    附:
    合同商品明细表和合同商品附件表的字段基本上没有什么差别,原本一张表就可以解决,所以才会有一个字段是“是否是附件”,以用来做区分。之所以后来又用两张表来区分开,有两个原因:①拆开后关系更加明确。②后期的业务主要围绕合同商品明细表,每次都要区分表中的某条记录是否属于合同商品明细记录,很麻烦。用两张表区分开,就不需要在代码中每次都区分了。

    建表成功
    从pdm中执行3张表的建表语句,注意无需执行关系语句。

    6、编写映射文件(Contract.hbm.xml、ContractProduct.hbm.xml、ExtCproduct.hbm.xml)
    Contract.hbm.xml

    <?xml version="1.0" encoding= "UTF-8"?>
             <property name="offeror" column="OFFEROR" type="string" />
             <property name="contractNo" column="CONTRACT_NO" type="string" />
             <property name="signingDate" column="SIGNING_DATE" type="timestamp" />
             <property name="inputBy" column="INPUT_BY" type="string" />
             <property name="checkBy" column="CHECK_BY" type="string" />
             <property name="inspector" column="INSPECTOR" type="string" />
             <property name="totalAmount" column="TOTAL_AMOUNT" type="big_decimal" />
             <property name="crequest" column="REQUEST" type="string" />
             <property name="customName" column="CUSTOM_NAME" type="string" />
             <property name="shipTime" column="SHIP_TIME" type="timestamp" />
             <property name="importNum" column="IMPORT_NUM" type="integer" />
             <property name="deliveryPeriod" column="DELIVERY_PERIOD" type="timestamp" />
             <property name="remark" column="REMARK" type="string" />
             <property name="printStyle" column="PRINT_STYLE" type="string" />
             <property name="oldState" column="OLD_STATE" type="integer" />
             <property name="state" column="STATE" type="integer" />
             <property name="outState" column="OUT_STATE" type="integer" />
             <property name="tradeTerms" column="TRADE_TERMS" type="string" />
            
             <property name="createBy" column="CREATE_BY" type="string" />
             <property name="createDept" column="CREATE_DEPT" type="string" />
             <property name="createTime" column="CREATE_TIME" type="timestamp" />      
                  
             <!-- 关联关系 -->
             <set name="contractProduct" inverse="true" cascade="all" lazy="false" order-by= "ORDER_NO">
                   <key>
                         <column name="CONTRACT_ID" ></column>
                   </key>
                   <one-to-many class="ContractProduct" />
             </set>
       </class>
    
    附: ①数据库表中为Number类型的字段,映像文件中对应的字段类型就为big_decimal。第一、精度高。第二、包含了double、float等类型。 ②MyEclipse中的快捷键:选中某些内容高亮,然后按下Ctrl+Shift+Y就可以将所选中内容变小写,对应的按下Ctrl+Shift+X,变大写。 ③使用Set集合管理合同商品明细,并不能使合同商品按照顺序显示,所以上面的set标签中就通过标签属性order-by确定按照“ORDER_NO”来排序。

    注:
    技术要点:如何映射布尔型的属性?
    在xxx.hbm.xml中映射布尔类型

    注意:
    1、数据库没有布尔型,都会映射为整数类型,例如:mysql中会转换为tinyint,其他数据库类同。
    2、PDM数据库建模时字段类型用bit,SQLSERVER2000为tinyint,MYSQL5.0为二进制字段。
    3、PO对象中布尔型变量还有get和set方法吗?
    private boolean accessories ;
    public boolean isAccessories() {
    return accessories ;
    }
    public void setAccessories(boolean accessories) {
    this.accessories = accessories;
    }
    由上可以看到,boolean(非包装类)类型的成员变量是没有get方法的,只有isXXX方法。

    ContractProduct.hbm.xml

    <?xml version="1.0" encoding= "UTF-8"?>
             <property name="productName" column="PRODUCT_NAME" type="string" />
             <property name="productNo" column="PRODUCT_NO" type="string" />
             <property name="productImage" column="PRODUCT_IMAGE" type="string" />
             <property name="productDesc" column="PRODUCT_DESC" type="string" />
             <property name="loadingRate" column="LOADING_RATE" type="string" />
            
             <property name="packingUnit" column="PACKING_UNIT" type="string" />
             <property name="cnumber" column="CNUMBER" type="integer" />
             <property name="outNumber" column="OUT_NUMBER" type="integer" />
             <property name="finished" type="boolean" column="FINISHED" />
            
             <property name="grossWeight" column="GROSS_WEIGHT" type="big_decimal" />
             <property name="netWeight" column="NET_WEIGHT" type="big_decimal" />
            
             <property name="sizeLength" column="SIZE_LENGTH" type="big_decimal" />
             <property name="sizeWidth" column="SIZE_WIDTH" type="big_decimal" />
             <property name="sizeHeight" column="SIZE_HEIGHT" type="big_decimal" />
            
             <property name="productRequest" column="PRODUCT_REQUEST" type="string" />
             <property name="price" column="PRICE" type="big_decimal" />
             <property name="amount" column="AMOUNT" type="big_decimal" />
            
             <property name="cunit" column="CUNIT" type="string" />
             <property name="boxNum" column="BOX_NUM" type="integer" />
             <property name="exPrice" column="EX_PRICE" type="big_decimal" />
             <property name="exUnit" column="EX_UNIT" type="string" />
             <property name="noTax" column="NO_TAX" type="big_decimal" />
             <property name="tax" column="TAX" type="big_decimal" />
             <property name="costPrice" column="COST_PRICE" type="big_decimal" />
             <property name="costTax" column="COST_TAX" type="big_decimal" />
             <property name="orderNo" column="ORDER_NO" type="integer" />
             <property name="accessories" type="boolean" column="ACCESSORIES"/>
    
             <many-to-one name="contract" column="CONTRACT_ID" class="Contract" lazy="false"/>
             <many-to-one name="factory" class="cn.itcast.entity.Factory" lazy="false" >
                   <column name="FACTORY_ID" length="40" />
             </many-to-one>           
             <set name="extCproduct" inverse="true" cascade="all" lazy="false" order-by= "ORDER_NO">
                   <key>
                         <column name="CONTRACT_PRODUCT_ID" />
                   </key>
                   <one-to-many class="cn.itcast.entity.ExtCproduct" />
             </set>             
       </class>
    

    ExtCproduct.hbm.xml

    <?xml version="1.0" ?>
             <property name="ctype" column="CTYPE" type="integer" />
             <property name="typeName" type="string" formula="(select c.NAME from SYS_CODE_B c where c.ORDER_NO=CTYPE and c.PARENT_ID='0104')" insert="false" update="false"  />
            
             <property name="productName" column="PRODUCT_NAME" type="string" />
             <property name="productNo" column="PRODUCT_NO" type="string" />
             <property name="productImage" column="PRODUCT_IMAGE" type="string" />
             <property name="productDesc" column="PRODUCT_DESC" type="string" />
             <property name="loadingRate" column="LOADING_RATE" type="string" />
            
             <property name="packingUnit" column="PACKING_UNIT" type="string" />
             <property name="cnumber" column="CNUMBER" type="integer" />
             <property name="outNumber" column="OUT_NUMBER" type="integer" />
             <property name="finished" type="boolean" column="FINISHED" />
            
             <property name="grossWeight" column="GROSS_WEIGHT" type="big_decimal" />
             <property name="netWeight" column="NET_WEIGHT" type="big_decimal" />
            
             <property name="sizeLength" column="SIZE_LENGTH" type="big_decimal" />
             <property name="sizeWidth" column="SIZE_WIDTH" type="big_decimal" />
             <property name="sizeHeight" column="SIZE_HEIGHT" type="big_decimal" />
            
             <property name="productRequest" column="PRODUCT_REQUEST" type="string" />
             <property name="price" column="PRICE" type="big_decimal" />
             <property name="amount" column="AMOUNT" type="big_decimal" />
            
             <property name="cunit" column="CUNIT" type="string" />
             <property name="boxNum" column="BOX_NUM" type="integer" />
             <property name="exPrice" column="EX_PRICE" type="big_decimal" />
             <property name="exUnit" column="EX_UNIT" type="string" />
             <property name="noTax" column="NO_TAX" type="big_decimal" />
             <property name="tax" column="TAX" type="big_decimal" />
             <property name="costPrice" column="COST_PRICE" type="big_decimal" />
             <property name="costTax" column="COST_TAX" type="big_decimal" />
             <property name="orderNo" column="ORDER_NO" type="integer" />
            
             <property name="accessories" type="boolean" column="ACCESSORIES" />
            
             <!-- Associations -->
             <many-to-one name="factory" class="cn.itcast.entity.Factory" lazy="false" >
                   <column name="FACTORY_ID" length="40" />
             </many-to-one>
             <many-to-one name="contractProduct" class="cn.itcast.entity.ContractProduct" lazy="false">
                   <column name="CONTRACT_PRODUCT_ID" length="40" />
             </many-to-one>
       </class>
    
    注: 一个生产厂家对应多个合同商品或者合同附件,然而,工厂类对应的映射文件中并没有配置相关的set集合,而合同商品和合同附件对应的配置文件中却配置了many-to-one标签。其实,这是由需求决定的。我们有通过某件合同商品或者合同附件找到其生产厂家的业务需求。但是,没有通过生产厂家找到对应的合同商品或者合同附件的业务需求。

    7、编写PO文件(Contract.java、ContractProduct.java、ExtCproduct.java)
    Contract.java
    public class Contract {
    private Set contractProduct ;

       private java.lang.String id ;
      
       private java.lang.String offeror ;
       private java.lang.String contractNo ;
       private java.util.Date signingDate ;
       private java.lang.String inputBy ;
       private java.lang.String checkBy ;
      
       private java.lang.String inspector ;
       private java.math.BigDecimal totalAmount ;
       private java.lang.String crequest ;
       private java.lang.String customName ;
       private java.util.Date shipTime ;
       private java.lang.Integer importNum ;
       private java.util.Date deliveryPeriod ;
       private java.lang.String remark ;
       private java.lang.String tradeTerms ;
       private java.lang.String printStyle ;
       private java.lang.Integer oldState ;
       private java.lang.Integer state ;
       private java.lang.Integer outState ;
       private java.lang.String createBy ;
       private java.lang.String createDept ;
       private java.util.Date createTime ;
       ......
    

    }

    ContractProduct.java
    public class ContractProduct {
    private Factory factory ;

       private Contract contract ;
    
       private Set<ExtCproduct> extCproduct ;
      
       private java.lang.String id ;
      
       private java.lang.String productName ;
       private java.lang.String productNo ;
       private java.lang.String productImage ;
       private java.lang.String productDesc ;
       private java.lang.String loadingRate ;
       private java.lang.String packingUnit ;
       private java.lang.Integer cnumber ;
       private java.lang.Integer outNumber ;
       private boolean finished ;
       private java.math.BigDecimal grossWeight ;
       private java.math.BigDecimal netWeight ;
       private java.math.BigDecimal sizeLength ;
       private java.math.BigDecimal sizeWidth ;
       private java.math.BigDecimal sizeHeight ;
       private java.lang.String productRequest ;
       private java.math.BigDecimal price ;
       private java.math.BigDecimal amount ;
       private java.lang.String cunit ;
       private java.lang.Integer boxNum ;
       private java.math.BigDecimal exPrice ;
       private java.lang.String exUnit ;
       private java.math.BigDecimal noTax ;
       private java.math.BigDecimal tax ;
       private java.math.BigDecimal costPrice ;
       private java.math.BigDecimal costTax ;
       private java.lang.Integer orderNo ;
       private boolean accessories ;
       .....
    

    }

    ExtCproduct.java
    public class ExtCproduct {

       private Factory factory ;
      
       private ContractProduct contractProduct ;
      
       private java.lang.String id ;
      
       private java.lang.Integer ctype ;
       private java.lang.String typeName ;
       private java.lang.String productName ;
       private java.lang.String productNo ;
       private java.lang.String productImage ;
       private java.lang.String productDesc ;
       private java.lang.String loadingRate ;
      
       private java.lang.String packingUnit ;
       private java.lang.Integer cnumber ;
       private java.lang.Integer outNumber ;
       private boolean finished ;
       private java.math.BigDecimal grossWeight ;
       private java.math.BigDecimal netWeight ;
       private java.math.BigDecimal sizeLength ;
       private java.math.BigDecimal sizeWidth ;
       private java.math.BigDecimal sizeHeight ;
       private java.lang.String productRequest ;
       private java.math.BigDecimal price ;
       private java.math.BigDecimal amount ;
       private java.lang.String cunit ;
       private java.lang.Integer boxNum ;
       private java.math.BigDecimal exPrice ;
       private java.lang.String exUnit ;
       private java.math.BigDecimal noTax ;
       private java.math.BigDecimal tax ;
       private java.math.BigDecimal costPrice ;
       private java.math.BigDecimal costTax ;
       private java.lang.Integer orderNo ;
       private boolean accessories ;
       .....
    

    }

    8、编写dao
    ContractDAO.java
    public class ContractDAO extends _RootDAO {

    }

    ContractProductDAO.java
    public class ContractProductDAO extends _RootDAO {

    }

    ExtContractDAO.java
    public class ExtCproductDAO extends _RootDAO {

    }

    9、在hibernate.cfg.xml中声明

    10、在beans.xml中声明

    11、创建Action(ContractAction.java、ContractProductAction.java、ExtCproductAction.java)
    ContractAction.java
    public class ContractAction extends _BaseStruts2Action implements ModelDriven {
    private Contract model = new Contract();
    public Contract getModel() {
    return model ;
    }

       //列表
       public String list(){
            ContractDAO oDao = (ContractDAO) this.getDao("daoContract" );
            List<Contract> dataList = oDao.find("from Contract o");
            ActionContext. getContext().put("dataList", dataList);
            
            return "plist" ;
      }
    
       //转向新增页面
       public String tocreate(){
            return "pcreate" ;
      }
      
       //转向修改页面
       public String toupdate(){
            ContractDAO oDao = (ContractDAO) this.getDao("daoContract" );
            Contract obj = (Contract) oDao.get(Contract. class, model.getId());
            ActionContext. getContext().getValueStack().push(obj);
            
            return "pupdate" ;
      }
      
       //转向查看页面
       public String toview(){
            ContractDAO oDao = (ContractDAO) this.getDao("daoContract" );
            Contract obj = (Contract) oDao.get(Contract. class, model.getId());
            ActionContext. getContext().getValueStack().push(obj);
            
            return "pview" ;
      }
      
       //保存
       public String save() throws ParseException{
            ContractDAO oDao = (ContractDAO) this.getDao("daoContract" );
             //初始化
             if(UtilFuns.isEmpty( model.getId())){
                   model.setState(0);            //0草稿 1已上报待报运
                   model.setCrequest(model .getCrequest().replaceFirst("deliveryPeriod", UtilFuns.formatDateTimeCN(UtilFuns.dateTimeFormat(model .getDeliveryPeriod()))));
            }
            oDao.saveOrUpdate( model);
             return list();
      }
      
       //删除
       public String delete(){
            String[] ids = model.getId().split(", " );
            ContractDAO oDao = (ContractDAO) this.getDao("daoContract" );
            oDao.deleteAllById(ids, Contract. class);
            
            return list();
      }
      
       //上报      0草稿 1已上报待报运
       public String submit(){
             this.chstate(1);
             return list();
      }
      
       //取消      0草稿 1已上报待报运
       public String cancelsubmit(){
             this.chstate(0);
             return list();
      }
      
       //修改状态 1正常0停用
       private void chstate(Integer value){
            String[] ids = model.getId().split(", " );       //注意分隔符
            Contract contract = null;
            Set oSet = new HashSet();
            ContractDAO oDao = (ContractDAO) this.getDao("daoContract" );
             for(int i=0;i<ids.length;i++){
                  contract = (Contract) oDao.get(Contract. class, ids[i]);
                  contract.setState(value);
                  
                  oSet.add(contract);
            }
            oDao.saveOrUpdateAll(oSet);                //批量保存
      }
    

    }
    附:
    UtilFuns类中的isEmpty方法的代码:
    public static boolean isEmpty (String str){
    try{
    if(str== null || str.equals(“null” ) || str.equals(“”)){
    return true ;
    }
    return false;
    }catch(Exception e){
    return false;
    }
    }
    由上面代码可以看到,当id为null或者为字符串“null”或者为空字符,那么就返回空。

    ContractProductAction.java
    public class ContractProductAction extends _BaseStruts2Action implements ModelDriven {
    private ContractProduct model = new ContractProduct();
    public ContractProduct getModel() {
    return model ;
    }

       //转向编辑页面
       public String toedit(){
            //准备数据 生产厂家
            FactoryDAO factoryDAO = (FactoryDAO) this.getDao("daoFactory" );
            List<Factory> factoryList = factoryDAO.find("from Factory o where o.state='1' and o.ctype='1'") ;             
            //state='1' 启用状态 ctype='1'货物的生产厂家
            ActionContext. getContext().put("factoryList", factoryList);
            
            ContractProductDAO oDao = (ContractProductDAO) this.getDao("daoContractProduct" );
            //得到当前合同下的所有货物
            List<ContractProduct> cpList = oDao.find("from ContractProduct o where o.contract.id='" + model.getContract().getId() + "' order By o.orderNo" );
            ActionContext. getContext().put("cpList", cpList);
            
            return "pedit" ;
      }
      
       //保存      
       public String save(){
            ContractProductDAO oDao = (ContractProductDAO) this.getDao("daoContractProduct" );
            oDao.saveOrUpdate( model);
    
             return toedit();        //转向编辑页面
      }
      
       //删除
       public String delete(){
            ContractProductDAO oDao = (ContractProductDAO) this.getDao("daoContractProduct" );
            oDao.delete( model.getId(), ContractProduct.class);
            
            return toedit();
      }
    

    }

    ExtCproductAction.java
    public class ExtCproductAction extends _BaseStruts2Action implements ModelDriven {
    private ExtCproduct model = new ExtCproduct();
    public ExtCproduct getModel() {
    return model ;
    }

       //转向编辑页面
       public String toedit(){
            //准备数据 生产厂家
            FactoryDAO factoryDAO = (FactoryDAO) this.getDao("daoFactory" );
            List<Factory> factoryList = factoryDAO.find("from Factory o where o.state='1' and o.ctype='2'") ;             
            //state='1' 启用状态 ctype='2'附件的生产厂家
            ActionContext. getContext().put("factoryList", factoryList);
            
            ExtCproductDAO oDao = (ExtCproductDAO) this.getDao("daoExtCproduct" );
            //得到当前合同下的所有货物
            List<ExtCproduct> epList = oDao.find("from ExtCproduct o where o.contractProduct.id='" + model.getContractProduct().getId() + "' order By o.orderNo");
            ActionContext. getContext().put("dataList", epList);
            
            return "pedit" ;
      }
      
       //保存      
       public String save(){
            ExtCproductDAO oDao = (ExtCproductDAO) this.getDao("daoExtCproduct" );
            Arith arith = new Arith();
             //计算金额
            model.setAmount(new BigDecimal(Arith.mul(Double.valueOf(model .getCnumber()),model.getPrice().doubleValue())));
            
            oDao.saveOrUpdate( model);
            
             //计算合同的总金额
             //...
    
            return toedit();        //转向编辑页面
      }
      
       //删除
       public String delete(){
            ExtCproductDAO oDao = (ExtCproductDAO) this.getDao("daoExtCproduct" );
            oDao.delete( model.getId(), ExtCproduct.class);
            
            return toedit();
      }
    

    }
    注:
    技术要点:如何实现默认值设置?
    数据库字段不设置默认值,那何时设置?
    答:新建保存时。

    Save方法就一个,如何判断新增还是修改?
    答:通过页面隐藏域。新增页面无id隐藏域,修改页面有id隐藏域。就可以通过id是否为null来判别。

    ContractAction.java
    public String save(){
    ContractDAO oDao = (ContractDAO) this.getDao(“daoContract” );
    if(UtilFuns.isEmpty(model.getId())){
    model. setState(0); //草稿
    }
    oDao.saveOrUpdate(model);

    return list();
    

    }

    12、创建合同页面(jContractList.jsp、jContractCreate.jsp、jContractUpdate.jsp、jContractView.jsp)(全码见源代码)
    入口链接:
    left.jsp
    < li>合同管理
    注:
    技术要点:列表页面中的字段怎么来的?
    业务中表的字段很多,列表中无法全部显示,就需要取舍,放哪些字段,哪些不放,怎么确定呢?
    ·通常是用户提供,通过和用户的交流确定。
    ·也可根据经验来先行编写,之后再跟用户确定。

    通常的原则是:
    1、重要的字段,客户最想看到的内容放页面上。
    2、如果是大段文字的字段,不放在列表页面上。如果客户需要,则进行截断显示。

    例如:
    要显示:产品与封样无明显差异,唛头、标签及包装质量务必符合公司要求。
    只显示:“产品与封样无明显差异…”,鼠标移动到文字上时,显示全部内容。

    技术要点:如果表字段名使用了系统关键字会如何?
    页面调用时,使用EL表达式取值时,将得到“意想不到”的结果。${request}得到的是request对象,不是合同表的request字段。那在不修改数据库表的结构的情况下,如果修改呢?

    答:修改字段映射,修改PO对象,修改页面调用,改request为crequest。

    (数据库设计时,感觉会跟关键字重名,就在其前面加个C)

    13、Struts配置
    创建struts-cargo.xml

    <?xml version="1.0" encoding= "UTF-8"?> /cargo/contract/jContractView.jsp /cargo/contract/jContractList.jsp /cargo/contract/jContractCreate.jsp /cargo/contract/jContractUpdate.jsp struts.xml < include file ="struts2/struts-cargo.xml" />

    14、测试合同功能
    测试列表显示
    向数据库中插入测试数据

    测试新增

    测试修改

    测试查看

    测试删除

    注:
    为了防止表单在Get方式时提交出现乱码问题,在Tomcat的配置文件server.xml中配置URIEncoding属性值为“UTF-8”。

    09 购销合同之商品与附件功能实现
    15、为购销合同添加货物并且列表显示
    ContractProductAction.java
    public class ContractProductAction extends _BaseStruts2Action implements ModelDriven {
    private ContractProduct model = new ContractProduct();
    public ContractProduct getModel() {
    return model ;
    }

       //转向编辑页面
       public String toedit(){
             //准备数据 生产厂家
            FactoryDAO factoryDAO = (FactoryDAO) this.getDao("daoFactory" );
            //state='1' 启用状态 ctype='1'货物的生产厂家
            List<Factory> factoryList = factoryDAO.find("from Factory o where o.state='1' and o.ctype='1'") ;             
            ActionContext. getContext().put("factoryList", factoryList);
            
            ContractProductDAO oDao = (ContractProductDAO) this.getDao("daoContractProduct" );
             //得到当前合同下的所有货物
            List<ContractProduct> cpList = oDao.find("from ContractProduct o where o.contract.id='" + model.getContract().getId() + "' order By o.orderNo" );
            ActionContext. getContext().put("cpList", cpList);
            
             return "pedit" ;
      }
       
       //保存      
       public String save(){
            ContractProductDAO oDao = (ContractProductDAO) this.getDao("daoContractProduct" );
            oDao.saveOrUpdate( model);
    
             return toedit();        //转向编辑页面
      }
    

    }
    附:
    由于新增和列表页面合并,在编辑方法中toedit,准备列表的数据。

    struts-cargo.xml

    /cargo/contract/jContractProductCreate.jsp

    jContractList.jsp

    jContractProductCreate.jsp
    <s:form name=“nuform” method=“post”>


    注:
    通过上面的方式传递合同的id,将使在Action中保存货物时,无需关心关联的对象,保存自己即可。

    序号货号装率数量包装单位单价操作
    < s:property value ="#line.index+1"/> ${productNo} ${loadingRate} ${cnumber} ${packingUnit} ${price}
    附: 购销合同的“上报”与“取消”功能与生产厂家的“启用”和“停用”功能类似,这里不再赘述。

    技术要点:货物新增时,如何知道是为哪个合同添加货物?
    怎样传递参数?
    方法有三种方法:
    1、通过po对象,利用struts2的model对象
    2、在action中声明属性(推荐)
    3、直接从request中获取(原始)

    合同jContractList.jsp列表页面在每条合同信息后增加下面的按钮:

    Action中接参:
    1、model对象方式: model.getContract().getId()
    2、request方式:String id = request.getParameter(“contract.id”);

    测试为购销合同添加货物

    附:
    装率就是一个大箱子能够装小包装箱个数的倒数,即装率=箱数/数量。

    16、为购销合同货物添加附件并且列表显示
    ExtCproductAction.java
    //保存
    public String save(){
    ExtCproductDAO oDao = (ExtCproductDAO) this.getDao(“daoExtCproduct” );
    Arith arith = new Arith();
    //计算金额,这里使用BigDecimal的原因,是因为java中直接对浮点数进行乘除都会产生误差
    model.setAmount(new BigDecimal(Arith.mul(Double.valueOf(model .getCnumber()),model.getPrice().doubleValue())));

      oDao.saveOrUpdate( model);
    
       return toedit();        //转向编辑页面
    

    }
    附:
    本功能与“为购销合同添加货物”功能类似,这里不再赘述。

    测试为购销合同货物添加附件

    17、删除购销合同下的货物
    ContractProductAction.java
    //删除
    public String delete(){
    ContractProductDAO oDao = (ContractProductDAO) this.getDao(“daoContractProduct” );
    oDao.delete( model.getId(), ContractProduct.class);

      return toedit();
    

    }

    jContractList.jsp

    附:
    “删除购销合同货物下的附件”功能与此功能类似,这里不再赘述。

    测试删除购销合同下的货物

    18、统计合同下货物和附件的数据量
    jContractList.jsp
    <s:property value=“contractProduct.size()” />
    /
    <s:set var=“extNumuber” value=“0”></ s:set>
    <s:iterator value=“#cp.contractProduct” var=“xcp”>
    <s:set var=“extNumuber” value=“#extNumuber+#xcp.extCproduct.size” ></s:set>
    </s:iterator>
    <s:property value=“#extNumuber” />

    19、复制合同
    原理:得到要复制的合同,创建新合同对象,get要复制的合同的属性,set到新合同的属性中。
    ContractAction.java(方案一)
    public String copy(){
    /*
    * 1. 获取数据
    * 2. 设置get/set,
    * 3. 保存
    *
    */
    ContractDAO oDao = (ContractDAO) this.getDao(“daoContract” );
    Contract oldContract = (Contract) oDao.get(Contract. class, model.getId());

      Contract newContext = new Contract();
      newContext.setCheckBy(oldContract.getCheckBy());
      newContext.setContractNo( "[复制]"+oldContract.getContractNo());
      newContext.setCustomName(oldContract.getCustomName());
      
       //初始化
      newContext.setState(0);        //0草稿
      newContext.setOutState(0);     //出货状态
      
       //获取货物
      Set<ContractProduct> cpSet = new HashSet();
      ContractProduct newContractProduct;
       for(ContractProduct cp:oldContract.getContractProduct()){
            newContractProduct = new ContractProduct();
            newContractProduct.setProductNo(cp.getProductNo());
            newContractProduct.setProductDesc(cp.getProductDesc());
            newContractProduct.setCnumber(cp.getCnumber());
            newContractProduct.setPrice(cp.getPrice());
            newContractProduct.setAmount(cp.getAmount());
            
             //初始化
            newContractProduct.setOutNumber(0);
            
             //绑定关系
            newContractProduct.setContract(newContext);
            cpSet.add(newContractProduct);
            
             //获取附件
            Set<ExtCproduct> epSet = new HashSet();
            ExtCproduct newExtCproduct;
             for(ExtCproduct ep:cp.getExtCproduct()){
                  newExtCproduct = new ExtCproduct();
                  newExtCproduct.setCnumber(ep.getCnumber());
                  newExtCproduct.setPrice(ep.getPrice());
                  
                   //初始化
                  newExtCproduct.setOutNumber(0);
                  
                   //绑定关系
                  newExtCproduct.setContractProduct(newContractProduct);
                  epSet.add(newExtCproduct);
            }
            newContractProduct.setExtCproduct(epSet);
      }
      
      newContext.setContractProduct(cpSet);
      oDao.saveOrUpdate(newContext);
      
      return list();
    

    }

    ContractAction.java(方案二)
    //复制
    public String copy(){
    ContractDAO oDao = (ContractDAO) this.getDao(“daoContract” );
    Contract contract = (Contract) oDao.get(Contract. class, model.getId());
    contract.setId( null);
    contract.setContractNo( “[复制]”+contract.getContractNo());
    oDao.saveOrUpdate(contract);

      return list();
    

    }

    测试复制功能

    10 使用POI技术生成出货表
    1、业务逻辑
    根据合同和指定的船期月份,统计当月的出货情况。

    2、技术要点

    3、添加日期控件
    OutProductAction.java
    public class OutProductAction extends _BaseStruts2Action{
    private String inputDate ;

       public String getInputDate() {
             return inputDate ;
      }
    
       public void setInputDate(String inputDate) {
             this.inputDate = inputDate;
      }
       //转入编辑页面
       publicString toedit(){
             return "pedit" ;
      }
    

    }

    jOutProduct.jsp
    < script type =“text/javascript” src =“…/…/js/datepicker/WdatePicker.js”>

    船期年月:

    < li id =“save”>打印</ a>

    struts-cargo.xml


    /cargo/outproduct/jOutProduct.jsp

    jContractList.jsp
    < li id =“new”>出货表

    测试日期控件

    4、POI基本操作
    OutProductAction.java
    //打印
    public void print() throws Exception{

       //1、创建excel文件
      HSSFWorkbook wb = new HSSFWorkbook();
      
       //2、创建工作簿
      HSSFSheet sheet=wb.createSheet();
      
       //3、创建行对象
      HSSFRow row = sheet.createRow(10); //第11行
      
       //4、创建单元格
      HSSFCell cell = row.createCell(( short)5); //第6列
      
       //5、设置单元格内容
      cell.setCellValue( "我是单元格" );
      
       //6、设置样式
       cell.setCellStyle(title(wb));
    
       //7、生成excel文件
      FileOutputStream fOut = new FileOutputStream("d:\\testpoi.xls" );
      wb.write(fOut);
      fOut.close();
    

    }

    private HSSFCellStyle title(HSSFWorkbook wb){
    HSSFCellStyle curStyle = wb.createCellStyle(); //创建样式
    HSSFFont curFont=wb.createFont(); //创建字体
    curFont.setCharSet(HSSFFont. DEFAULT_CHARSET); //设置中文字体,那必须还要再对单元格进行编码设置
    curFont.setFontName( “宋体”);
    curFont.setFontHeightInPoints(( short)16);
    curFont.setBoldweight(HSSFFont. BOLDWEIGHT_BOLD);
    curStyle.setFont(curFont); //绑定字体

      curStyle.setAlignment(HSSFCellStyle. ALIGN_CENTER);                  //横向居中
      curStyle.setVerticalAlignment(HSSFCellStyle. VERTICAL_CENTER);      //纵向居中
      
      curStyle.setBorderTop(HSSFCellStyle. BORDER_THIN);
      curStyle.setBorderLeft(HSSFCellStyle. BORDER_THIN);
      curStyle.setBorderRight(HSSFCellStyle. BORDER_THIN);
      curStyle.setBorderBottom(HSSFCellStyle. BORDER_THIN);  
      
      return curStyle;
    

    }

    测试

    注:
    ①设置单元格样式时,如果执行cell.setCellStyle(title(wb));cell.setCellStyle(box(wb));。那么,只有最后一句样式设置生效,前面所有的设置都将无效。因此,单元格设置样式时不能多次设置,一旦单元格有任何样式的变动,都要重新写一个方法,而不能通过执行多个样式方法达到同样的效果,这是POI的缺点之一。
    ②POI后期版本与前期版本不兼容,本项目选择3.0.2-Final版。
    ③之所以选用POI做报表原因有三:1、其他报表工具需要公司购买,提高了成本。2、需要在IE浏览器上装插件,不利于用户操作。3、公司工作人员已经能够熟练使用Excel。

    附:
    为以上代码添加下载功能。
    DownloadBaseAction.java
    /**

    • @param file 要下载的文件

    • @param returnName 返回的文件名

    • @param response HttpServletResponse

    • @param delFlag 是否删除文件
      */
      public void prototypeDowload(File file,String returnName,HttpServletResponse response,boolean delFlag){
      // 下载文件
      FileInputStream inputStream = null;
      ServletOutputStream outputStream = null;
      try {
      if(!file.exists()) return;
      response.reset();
      //设置响应类型
      response.setContentType( “application/octet-stream”);
      //设置响应的文件名称,并转换成中文编码
      returnName = response.encodeURL( new String(returnName.getBytes(),“iso8859-1” )); //保存的文件名,必须和页面编码一致,否则乱码
      response.addHeader( “Content-Disposition”, “attachment;filename=” +returnName);
      //将文件读入响应流
      inputStream = new FileInputStream(file);
      outputStream = response.getOutputStream();
      int length = 1024;
      int readLength=0;
      byte buf[] = new byte[1024];
      readLength = inputStream.read(buf, 0, length);
      while (readLength != -1) {
      outputStream.write(buf, 0, readLength);
      readLength = inputStream.read(buf, 0, length);
      }

      } catch (Exception e) {
      e.printStackTrace();
      } finally {
      try {
      outputStream.flush();
      } catch (IOException e) {
      }
      try {
      outputStream.close();
      } catch (IOException e) {
      }
      try {
      inputStream.close();
      } catch (IOException e) {
      }
      //删除原文件
      if(delFlag) {
      file.delete();
      }
      }
      }

    OutProductAction.java
    //8下载
    HttpServletResponse response = ServletActionContext. getResponse();
    DownloadBaseAction down = new DownloadBaseAction();
    down.prototypeDowload(new File( “d:\testpoi.xls”), “testpoi.xls” , response, true);

    测试

    5、POI基本技巧
    1)创建或者打开excel文件(HSSFWorkbook)
    HSSFWorkbook wb = new HSSFWorkbook(); //新建
    HSSFWorkbook wb = new HSSFWorkbook(new FileInputStream(xlsFile)); //打开

    2)创建工作簿 sheet /获得
    HSSFSheet sheet = wb.createSheet(); //新建
    HSSFSheet sheet = wb.getSheetAt(0); //打开第一个工作簿

    3)合并单元格
    Region region = null; //合并单元格
    region = new Region(0, (short)(1), 0, (short)9);
    sheet.addMergedRegion(region); //绑定

    4)创建行对象
    HSSFRow nRow = sheet.createRow(行); //行开始值为0,
    nRow.setHeightInPoints(36f); //设置行高

    5)创建单元格
    HSSFCell nCell = nRow.createCell((short)列值); //列开始值为0,

    6)写内容
    nCell.setCellValue(“内容”);

    7)设置样式
    HSSFCellStyle curStyle = wb.createCellStyle(); //创建样式
    HSSFFont curFont = wb.createFont(); //创建字体
    curFont.setCharSet(HSSFFont.DEFAULT_CHARSET); //设置中文字体,那必须还要再对单元格进行编码设置
    curFont.setFontName(“黑体”);
    curFont.setFontHeightInPoints((short)12);
    curStyle.setFont(curFont); //绑定字体

    curStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); //横向居中
    curStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); //纵向居中

    curStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);
    curStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
    curStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
    curStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);

    注意:样式最大的问题,样式不能继承,不能覆盖。

    8)生成excel文件
    FileOutputStream fOut = new FileOutputStream(outDir + “outproduct.xls”); //创建excel文件结构
    wb.write(fOut); //写入内容
    fOut.close(); //关闭

    9)下载
    HttpServletResponse response = ServletActionContext.getResponse();
    DownloadBaseAction down = new DownloadBaseAction();
    down.prototypeDowload(new File(outDir + “outproduct.xls”), “testpoi.xls”, response, true);

    10)设置标题:
    将第一行作为标题,即每页都打印此行 sheetN,startCol,stopCol,startRow,stopRow
    wb.setRepeatingRowsAndColumns(0,1,8,0,1);

    11)页脚:
    HSSFFooter footer = sheet.getFooter();
    footer.setRight(“第”+HSSFFooter.page()+“页 共”+HSSFFooter.numPages()+"页 "); //页数

    6、使用POI生成出货表(使用模板生成出货表)
    UtilFuns.java
    public static String getROOTPath (){
    UtilFuns uf = new UtilFuns();
    return uf.getClass().getResource(“/” ).getPath().replace(“/WEB-INF/classes/”, “/”).substring(1);
    }

    PioUtils.java
    // 计算行高度,实现行自动适应高度 defaultRowHeight = 12.00f; //每一行的高度指定 目前只实现根据回车多行来判断,不能根据单元格宽度自动回行来判断
    public float getCellAutoHeight(String str, float defaultRowHeight) {
    if (str == null) {
    return defaultRowHeight;
    }
    float height = 0.00f;
    int n = 0;
    if (str.endsWith(“\n” )) {
    n = str.split( “\n”).length ; // 回车个数
    } else {
    n = str.split( “\n”).length + 1; // 回车个数
    }
    height = defaultRowHeight * n;

       return height; // 计算
    

    }

    OutProductAction.java
    //打印
    publicvoid print() throws Exception{
    int curRow=0;//当前行
    int colNo=1;//当前列

       //得到模板路径
      String rootPath = UtilFuns. getROOTPath();
      String xlsFile = rootPath + "/make/xlsprint/tOUTPRODUCT.xls" ;
      
       //新建临时目录,存放excel     /root/web/ tmpfile/yyyy -mm-dd/...
      String outDir = rootPath + "/web/tmpfile/" + UtilFuns.sysDate()+"/";
      File tmpDir = new File(outDir);
      if(!tmpDir.exists()){
            tmpDir.mkdirs();
      }
      
       //读取excel文件模板
      HSSFWorkbook wb = new HSSFWorkbook(new FileInputStream(xlsFile));
      
       //获取工作簿
      HSSFSheet sheet=wb.getSheetAt(0);
      
     //设置标题
      wb.setRepeatingRowsAndColumns(0,1,9,0,1);  // sheetN,startCol,stopCol,startRow,stopRow
      
       //页脚
      HSSFFooter footer = sheet.getFooter();
      footer.setRight( "第"+HSSFFooter.page()+ "页 共"+HSSFFooter.numPages()+ "页     " );  //页数
    
       //出货表标题第1行,1~9列合并
      Region region= null;
      region= new Region(0,(short)1,0,(short)9); 
      sheet.addMergedRegion(region); //绑定
      
       //设置字体
      PioUtil pioUtil= new PioUtil();
      HSSFFont defaultFont10=pioUtil.defaultFont10(wb);
      
       //设置行高
      HSSFRow nRow=sheet.createRow(curRow);
      nRow.setHeightInPoints(36f);
      
       //设置单元格内容
      HSSFCell nCell=nRow.createCell(( short)1); //设置一行中的单元格
      nCell.setCellValue( inputDate.replace("-0", "-").replace( "-", "年")+"月份出货表");
      
       //设置样式
      nCell.setCellStyle(title(wb));
      curRow++;
      
      curRow++;
      nRow=sheet.createRow(curRow);
      
       //取数据
      ContractProductDAO oDao =(ContractProductDAO)this .getDao("daoContractProduct");
      ContractProduct cp= null;
      String _extProducts= "";
      
       float height=0;
      List<ContractProduct> oList= oDao.find("from ContractProduct o where o.contract.shipTime like '"+ inputDate+"%'");
      
       for (int i=0;i<oList.size();i++){
            colNo=1;   //初始化列变量
            cp=oList.get(i);  //得到每个货物
            
            nRow=sheet.createRow(curRow);
            
            nCell = nRow.createCell(( short)colNo++);  
            nCell.setCellValue(cp.getContract().getCustomName());
            nCell.setCellStyle(pioUtil.notehv10_BorderThin(wb, defaultFont10));
            
            ......
            
            nCell = nRow.createCell(( short)colNo++);  
            _extProducts = "";      //清空值
             for(ExtCproduct ep:cp.getExtCproduct()){
                  _extProducts += ep.getTypeName() + UtilFuns. newLine();
            }
            _extProducts = UtilFuns. DelLastChar(_extProducts);
            
             //根据内容自动设置高度
            height = pioUtil. getCellAutoHeight(_extProducts, 12f);
            nRow.setHeightInPoints(height);
            
             if(UtilFuns.isEmpty(_extProducts)){
                   nCell.setCellValue("无" );                        //附件
            } else{
                   nCell.setCellValue(_extProducts);         //附件
            }
            nCell.setCellStyle(pioUtil.notehv10_BorderThin(wb, defaultFont10));
            
            nCell = nRow.createCell(( short)colNo++);  
            nCell.setCellValue(cp.getContract().getDeliveryPeriod());
            nCell.setCellStyle(pioUtil.notehv10_BorderThin(wb, defaultFont10));
            
            nCell = nRow.createCell(( short)colNo++);  
            nCell.setCellValue(cp.getContract().getShipTime());
            nCell.setCellStyle(pioUtil.notehv10_BorderThin(wb, defaultFont10));
            
            nCell = nRow.createCell(( short)colNo++);  
             nCell.setCellValue(cp.getContract().getTradeTerms()); 
            nCell.setCellStyle(pioUtil.notehv10_BorderThin(wb, defaultFont10));
      
            curRow++;
      }
       //生成excel文件
      FileOutputStream fOut = new FileOutputStream(outDir + "outproduct.xls" );             //创建excel文件结构
      wb.write(fOut);         
      fOut.close();     
      
       //下载
      HttpServletResponse response = ServletActionContext. getResponse();
      DownloadBaseAction down = new DownloadBaseAction();
      down.prototypeDowload( new File(outDir + "outproduct.xls" ), "testpoi.xls" , response, true);
    

    }

    private HSSFCellStyle title(HSSFWorkbook wb){
    HSSFCellStyle curStyle = wb.createCellStyle(); //创建样式
    HSSFFont curFont=wb.createFont(); //创建字体
    curFont.setCharSet(HSSFFont. DEFAULT_CHARSET); //设置中文字体,那必须还要再对单元格进行编码设置
    curFont.setFontName( “宋体”);
    curFont.setFontHeightInPoints(( short)16);
    curFont.setBoldweight(HSSFFont. BOLDWEIGHT_BOLD);
    curStyle.setFont(curFont); //绑定字体

      curStyle.setAlignment(HSSFCellStyle. ALIGN_CENTER);                       //横向居中
      curStyle.setVerticalAlignment(HSSFCellStyle. VERTICAL_CENTER);      //纵向居中
      
       return curStyle;
    

    }

    /**

    • 设置内容的样式和字体

    • @param wb

    • @return
      */
      private HSSFCellStyle subtitle(HSSFWorkbook wb){
      HSSFCellStyle curStyle = wb.createCellStyle(); //创建样式
      HSSFFont curFont = wb.createFont(); //创建字体
      curFont.setCharSet(HSSFFont. DEFAULT_CHARSET); //设置中文字体,那必须还要再对单元格进行编码设置
      curFont.setFontName( “黑体”);
      curFont.setFontHeightInPoints(( short)12);
      curStyle.setFont(curFont); //绑定字体

      curStyle.setAlignment(HSSFCellStyle. ALIGN_CENTER); //横向居中
      curStyle.setVerticalAlignment(HSSFCellStyle. VERTICAL_CENTER); //纵向居中

      curStyle.setBorderTop(HSSFCellStyle. BORDER_THIN);
      curStyle.setBorderLeft(HSSFCellStyle. BORDER_THIN);
      curStyle.setBorderRight(HSSFCellStyle. BORDER_THIN);
      curStyle.setBorderBottom(HSSFCellStyle. BORDER_THIN);

      return curStyle;
      

    }

    模板

    附:
    ①Excel能够存储的最大数据量?
    Excel2003(列:255,行:65535)
    Excel2007(列:16384,行:1048576)
    ②在设置单元格高度的时候,可以先调整Excel的单元格高度,然后获取数据,再在程序中进行设置。

    ③如果POI打印时报字体过多
    1)把字体对象的创建放到工具类中,这样执行完之后就可以释放。
    2)将字体对象设置为参数,样式设置为参数(推荐)。

    测试

    附:
    不使用模板生成出货表的代码如下:
    OutProductAction.java
    //打印
    public void print() throws IOException{
    int curRow = 0; //当前行
    int colNo = 1; //当前列

       //创建excel文件
      HSSFWorkbook wb = new HSSFWorkbook();
      
       //创建工作簿
      HSSFSheet sheet = wb.createSheet();
      
      //设置标题
      wb.setRepeatingRowsAndColumns(0,1,9,0,1);  // sheetN,startCol,stopCol,startRow,stopRow
      
       //页脚
      HSSFFooter footer = sheet.getFooter();
      footer.setRight( "第"+HSSFFooter.page()+ "页 共"+HSSFFooter.numPages()+ "页     " );  //页数
    
       //标题
      Region region = null;                            //合并单元格
      region = new Region(0, (short)(1), 0, (short)9);
      sheet.addMergedRegion(region);                   //绑定
      
      //设置字体
      PioUtil pioUtil = new PioUtil();
      HSSFFont defaultFont10 = pioUtil.defaultFont10(wb);                //设置字体
      
      HSSFRow nRow = sheet.createRow(curRow);
      nRow.setHeightInPoints(36f);
      
      HSSFCell nCell = nRow.createCell(( short)1);           
      nCell.setCellValue( inputDate.replace("-0", "-").replace( "-", "年")+"月份出货表");        //2013-08   2013-12
       
      //设置样式
      nCell.setCellStyle(title(wb));
     
       //标题头
      curRow++;
      nRow = sheet.createRow(curRow);
      nRow.setHeightInPoints(26.25f);            //设置行高
      
      sheet.setColumnWidth(( short)(colNo-1), (short)(300*0.5));    //设置A列宽度为宽度*300,从而获取像素值
      sheet.setColumnWidth(( short)colNo, (short)(300*25.75));
      nCell = nRow.createCell(( short)colNo++);  
      nCell.setCellValue( "客人");
      nCell.setCellStyle(subtitle(wb));
      
      ......
      
      nCell = nRow.createCell(( short)colNo++);  
      nCell.setCellValue( "贸易条款" );
      nCell.setCellStyle(subtitle(wb));
      
       //内容
      curRow++;
      nRow = sheet.createRow(curRow);
      
       //取数据
      ContractProductDAO oDao = (ContractProductDAO) this.getDao("daoContractProduct" );
      ContractProduct cp = null;
      String _extProducts = "";
      
       float height = 0;
      List<ContractProduct> oList = oDao.find("from ContractProduct o where o.contract.shipTime like '"+ inputDate+"%'");
      
       for(int i=0;i<oList.size();i++){
            colNo = 1;                           //初始化列变量
            cp = oList.get(i);                   //得到每个货物
      
            nRow = sheet.createRow(curRow);
            
            
            nCell = nRow.createCell(( short)colNo++);  
             nCell.setCellValue(cp.getContract().getCustomName());
            nCell.setCellStyle(pioUtil.notehv10_BorderThin(wb, defaultFont10));
            
            ......
            
            nCell = nRow.createCell(( short)colNo++);  
             nCell.setCellValue(cp.getFactory().getFactoryName());
            nCell.setCellStyle(pioUtil.notehv10_BorderThin(wb, defaultFont10));
            
            nCell = nRow.createCell(( short)colNo++);  
            _extProducts = "";      //清空值
             for(ExtCproduct ep:cp.getExtCproduct()){
                  _extProducts += ep.getTypeName() + UtilFuns. newLine();
            }
            _extProducts = UtilFuns. DelLastChar(_extProducts);
            
            height = pioUtil.getCellAutoHeight(_extProducts, 12f);
            nRow.setHeightInPoints(height);
            
             if(UtilFuns.isEmpty(_extProducts)){
                   nCell.setCellValue("无" );                        //附件
            } else{
                   nCell.setCellValue(_extProducts);         //附件
            }
            nCell.setCellStyle(pioUtil.notehv10_BorderThin(wb, defaultFont10));
            
            nCell = nRow.createCell(( short)colNo++);  
            nCell.setCellValue(cp.getContract().getDeliveryPeriod());
            nCell.setCellStyle(pioUtil.notehv10_BorderThin(wb, defaultFont10));
            
            nCell = nRow.createCell(( short)colNo++);  
            nCell.setCellValue(cp.getContract().getShipTime());
            nCell.setCellStyle(pioUtil.notehv10_BorderThin(wb, defaultFont10));
            
            nCell = nRow.createCell(( short)colNo++);  
             nCell.setCellValue(cp.getContract().getTradeTerms()); 
            nCell.setCellStyle(pioUtil.notehv10_BorderThin(wb, defaultFont10));
      
            curRow++;
      }
      
       //生成excel文件
      FileOutputStream fOut = new FileOutputStream("d:\\testpoi.xls" );             //创建excel文件结构
      wb.write(fOut);          //写入内容  
      fOut.close();            //关闭
      
       //下载
      HttpServletResponse response = ServletActionContext. getResponse();
      DownloadBaseAction down = new DownloadBaseAction();
      down.prototypeDowload( new File("d:\\testpoi.xls" ), "testpoi.xls", response, true);
    

    }
    11 使用POI技术生成购销合同
    1、购销合同

    2、POI重点操作
    ①分页
    sheet.setRowBreak(当前行); //设置分页符

    ②怎么插入一个图片
    HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); //add picture
    pioUtil.setPicture(wb, patriarch, rootPath+“make/xlsprint/logo.jpg”, curRow, 2, curRow+4, 2);

    ③怎么插入一条线
    pioUtil.setLine(wb, patriarch, curRow, 2, curRow, 8); //draw line

    ④设置数值类型(之所以设置某个单元格为数值类型,是因为其他单元格的数值是基于此单元格的数值计算出来的)
    nCell.setCellType(HSSFCell.CELL_TYPE_NUMERIC);

    ⑤设置前导符
    HSSFDataFormat format = wb.createDataFormat();
    return format.getFormat(““¥”#,###,##0.00”); // 设置格式

    ⑥设置公式
    nCell.setCellType(HSSFCell.CELL_TYPE_FORMULA);
    nCell.setCellFormula(“F”+String.valueOf(curRow)+“*H”+String.valueOf(curRow));

    nCell.setCellFormula(“SUM(I”+String.valueOf(curRow-4)+“:I”+String.valueOf(curRow-1)+“)”);

    3、实现代码(这里只列出部分重要代码,全码请见源代码)
    FileUtil.java
    /* 目录下已经有同名文件,则文件重命名,增加文件序号 add by tony 20110712 */
    public String newFile(String sPath, String sFile){
    String newFileName = new String();
    String withoutExt = new String();
    File curFile = new File(sPath + “\” + sFile);
    if (curFile.exists()) {
    for(int counter = 1; curFile.exists(); counter++){
    withoutExt = this.getNameWithoutExtension(curFile.getName());
    if(withoutExt.endsWith(counter-1 + “)” )){
    withoutExt = withoutExt.substring(0,withoutExt.indexOf(“(” )); //idea
    }
    newFileName = withoutExt + “(” + counter + “)” + “.” + getFileExt(curFile.getName());
    curFile = new File(sPath + “\” + newFileName);
    }
    } else{
    newFileName = curFile.getName();
    }
    return newFileName;
    }
    注:
    此方法是在生成临时文件的时候防止文件重命名而调用的方法。
    附:
    购销合同模板(只是设置好了每一列的宽度)

    ①以下代码是为了将每页的信息放入一个map结构中,将多页的信息放入一个ArrayList结构中,以供后面生成报表使用。
    ContractPrint.java
    /*

    • response 打印输出到response中,直接下载

    • */
      public void print(String contractId, HttpServletResponse response, ContractProductDAO oDao, ContractDAO pDao) throws Exception{
      //相同厂家的信息一起打印
      List oList = oDao.find(“from ContractProduct o where o.contract.id='”+contractId+ “’ order by o.factory.id,o.orderNo” );

      UtilFuns utilFuns = new UtilFuns();
      String rootPath = utilFuns.getROOTPath(); //获取虚拟路径

      String tempXlsFile = rootPath+ “make/xlsprint/tCONTRACT.xls” ; //获取模板文件

      FileUtil fu = new FileUtil();
      String sPath = “/web/tmpfile/”+utilFuns.sysDate ()+“/”; //临时目录
      fu.makeDir(rootPath+sPath) ;
      String sFile = fu.newFile(rootPath+sPath, “contract.xls”); //防止文件并发访问

      String outFile = rootPath+sPath+sFile;

      Contract contract = (Contract)pDao.get(Contract. class, contractId); //获得合同信息

      //填写每页的内容,之后在循环每页读取打印
      

      Map<String,String> pageMap = null;
      List< Map> pageList = new ArrayList() ; //打印页

      ContractProduct oProduct = null;
      String stars = “”;
      String oldFactory = “”;
      for(int i=0;i<oList.size();i++){
      oProduct = oList.get(i);
      pageMap = new HashMap(); //每页的内容

           pageMap.put( "Offeror", "收 购 方:" + contract.getOfferor());
           pageMap.put( "Factory", "生产工厂:" + oProduct.getFactory().getFullName());
           pageMap.put( "ContractNo", "合 同 号:" + contract.getContractNo());
           pageMap.put( "Contractor", "联 系 人:" + oProduct.getFactory().getContractor());
           pageMap.put( "SigningDate", "签单日期:" +UtilFuns.formatDateTimeCN (UtilFuns.dateTimeFormat(contract.getSigningDate())));
           pageMap.put( "Phone", "电    话:" + oProduct.getFactory().getPhone());
           pageMap.put( "InputBy", "制单:" + contract.getInputBy());
           pageMap.put( "CheckBy", "审单:" + utilFuns.fixSpaceStr(contract.getCheckBy(),26)+"验货员:" +utilFuns.convertNull(oProduct.getFactory().getInspector()));
            //pageMap.put("TotalAmount", String.valueOf(contract.getTotalAmount().doubleValue()));
            //pageMap.put("Remark", "  "+contract.getRemark());
           pageMap.put( "Request", "  " +contract.getCrequest());
           
           pageMap.put( "ProductImage", oProduct.getProductImage());
           pageMap.put( "ProductDesc", oProduct.getProductDesc());
           pageMap.put( "Cnumber", String.valueOf(oProduct.getCnumber().doubleValue()));
            if(oProduct.getPackingUnit().equals("PCS" )){
                 pageMap.put( "PackingUnit", "只" );
           } else if (oProduct.getPackingUnit().equals("SETS")){
                 pageMap.put( "PackingUnit", "套" );
           }
           pageMap.put( "Price", String.valueOf(oProduct.getPrice().doubleValue()));
            //pageMap.put("Amount", String.valueOf(oProduct.getAmount().doubleValue()));
           pageMap.put( "ProductNo", oProduct.getProductNo());
           
           oldFactory = oProduct.getFactory().getFactoryName();
           
            if(contract.getPrintStyle().equals("2" )){
                 i++;   //读取第二个货物信息
                  if(i<oList.size()){
                       oProduct = oList.get(i);
                       
                        if(oProduct.getFactory().getFactoryName().equals(oldFactory)){       //厂家不同另起新页打印,除去第一次的比较
                             
                             pageMap.put( "ProductImage2", oProduct.getProductImage());
                             pageMap.put( "ProductDesc2", oProduct.getProductDesc());
                             pageMap.put( "Cnumber2", String.valueOf(oProduct.getCnumber().doubleValue()));
                             pageMap.put( "Price2", String.valueOf(oProduct.getPrice().doubleValue()));
                              //pageMap.put("Amount2", String.valueOf(oProduct.getAmount().doubleValue()));
                             pageMap.put( "ProductNo2", oProduct.getProductNo());
                       } else{
                             i--;   //tip:list退回
                       }
                 } else{
                       pageMap.put( "ProductNo2", null );    //后面依据此判断是否有第二个货物
                 }
           }
           
           stars = "";
            for(int j=0;j<contract.getImportNum();j++){
                 stars += "★";
           }
           pageMap.put( "ContractDesc", stars+" 货物描述" );
           
           pageList.add(pageMap);
      

      }

      }

    ②设置图片

    PioUtil.java
    // 指定图片类型为 jpg
    public void setPicture(HSSFWorkbook wb, HSSFPatriarch patriarch,
    String pic, int iRowStart, int iColStart, int iRowStop, int iColStop)
    throws IOException {
    // 判断文件是否存在
    File imgFile = new File(pic);
    if (imgFile.exists()) {
    // 图片处理
    ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
    BufferedImage bufferImg = ImageIO. read(new File(pic));
    ImageIO. write(bufferImg, “jpg”, byteArrayOut);

             // 左,上(0-255),右(0-1023),下
            HSSFClientAnchor anchor = new HSSFClientAnchor(20, 1, 1018, 0,
                        ( short) (iColStart), iRowStart, (short) (iColStop),
                        iRowStop);
            patriarch.createPicture(anchor, wb.addPicture(byteArrayOut
                        .toByteArray(), HSSFWorkbook.PICTURE_TYPE_JPEG ));
      }
    

    }

    ContractPrint.java
    pioUtil.setPicture (wb, patriarch, rootPath+“make/xlsprint/logo.jpg”, curRow, 2, curRow+4, 2);

    ③划线

    PioUtil.java
    // 画线
    public void setLine(HSSFWorkbook wb, HSSFPatriarch patriarch,
    int iRowStart, int iColStart, int iRowStop, int iColStop) {
    HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 350, 0,
    ( short) (iColStart), iRowStart, (short) (iColStop), iRowStop);
    HSSFSimpleShape lineShape = patriarch.createSimpleShape(anchor);
    lineShape.setShapeType(HSSFSimpleShape. OBJECT_TYPE_LINE);
    }

    ContractPrint.java
    pioUtil.setLine(wb, patriarch, curRow, 2, curRow, 8); //draw line

    ④设置金额

    PioUtil.java
    public short rmb2Format (HSSFWorkbook wb) {
    HSSFDataFormat format = wb.createDataFormat();
    return format.getFormat(““¥”#,###,###.00” ); // 设置格式
    }

    ContractPrint.java
    Short rmb2Format = pioUtil.rmb2Format(wb); //设置格式

    ⑤设置公式

    ContractPrint.java
    if(UtilFuns.isNotEmpty(printMap.get( “Cnumber”))&&UtilFuns.isNotEmpty(printMap.get( “Price”))){
    nCell = nRow.createCell(( short)8);
    nCell.setCellType(HSSFCell. CELL_TYPE_FORMULA);
    nCell.setCellFormula( “SUM(I”+String.valueOf(curRow-4)+ “:I”+String.valueOf(curRow-1)+ “)”);
    nCell.setCellStyle(pioUtil.moneyrv12_BorderThin(wb,defaultFont12,rmb2Format));
    }

    ⑥设置总金额

    ContractPrint.java
    //TotalAmount
    nRow = sheet.createRow((short)curRow-1);
    nRow.setHeightInPoints(24);
    if(UtilFuns.isNotEmpty(printMap.get( “Cnumber”))&&UtilFuns.isNotEmpty(printMap.get( “Price”))){
    nCell = nRow.createCell(( short)8);
    nCell.setCellType(HSSFCell. CELL_TYPE_FORMULA);
    nCell.setCellFormula( “SUM(I”+String.valueOf(curRow-4)+ “:I”+String.valueOf(curRow-1)+ “)”);
    nCell.setCellStyle(pioUtil.moneyrv12_BorderThin(wb,defaultFont12,rmb2Format));
    }

    注:
    ①如果打开excel过程中出现如下错误:

    那么就把HSSFCellStyle、HSSFFont对象的创建次数降低,不要在样式方法里面创建,而是作为参数传递进去,并且只在外面创建一次。
    OutProductAction.java
    public HSSFCellStyle box(HSSFWorkbook wb, HSSFCellStyle curStyle, HSSFFont curFont) {

      curFont.setFontName( "Times New Roman");
      curFont.setCharSet(HSSFFont. DEFAULT_CHARSET); // 设置中文字体,那必须还要再对单元格进行编码设置
      curFont.setFontHeightInPoints(( short) 10);            
    
      curStyle.setWrapText( true); // 换行
      curStyle.setFont(curFont);
      curStyle.setVerticalAlignment(HSSFCellStyle. VERTICAL_CENTER); // 单元格垂直居中
    
      curStyle.setBorderTop(HSSFCellStyle. BORDER_THIN); // 实线右边框
      curStyle.setBorderRight(HSSFCellStyle. BORDER_THIN); // 实线右边框
      curStyle.setBorderBottom(HSSFCellStyle. BORDER_THIN); // 实线右边框
      curStyle.setBorderLeft(HSSFCellStyle. BORDER_THIN); // 实线右边框
    
       return curStyle;
    

    }

    12 出口报运(1)
    1、业务逻辑
    根据购销合同制定出口商品报运单。报运时可以将多个购销合同形成一单报运;也可以分多次运输货物。
    在报运中将增加货物的毛重、净重、长、宽、高、出口单价。

    2、功能描述及其分析

    3、技术要点

    4、数据库表设计&执行SQL
    三张表主从关系
    和合同一致,设计简单,复制数据简单

    注:
    之所以单独为报运单表创建商品表以及附件表,而不是使报运表和合同表建立关系从而通过合同表获取商品表以及附件表的数据。是为了提升程序效率。因为,后面的装箱等操作都会通过报运表获取商品表以及附件表数据。这样多层级的操作会严重降低程序的运行效率,不利于提升客户体验。并且将报运的多个合同的编号作为冗余字段放在报运单表中。

    附:
    报运表中包含了货物信息以及其他附加信息。例如:毛重、净重、长、宽、高。

    5、创建PO对象(Export.java、ExportProduct.java和ExtEproduct.java)
    Export.java
    public class Export {
    private Set exportProduct ;

       private java.lang.String id ;
       private java.lang.String contractIds ;
       private java.lang.String customerContract ;
       private java.util.Date inputDate ;
       private java.lang.String consignee ;
       private java.lang.String lcno ;
       ......
    

    }

    ExportProduct.java
    public class ExportProduct {

       private Factory factory ;
       private Export export ;  
       private Set<ExtEproduct> extEproduct ;
      
       private java.lang.String id ;
       private java.lang.String contractProductId ;
       private java.lang.String contractId ;
       private java.lang.String contractNo ;
       private java.lang.String productName ;
       private java.lang.String productNo ;
       private java.lang.String productImage ;
       private java.lang.String productDesc ;
       private java.lang.String loadingRate ;
       private java.lang.String packingUnit ;
       private java.lang.Integer cnumber ;
       private java.lang.Integer outNumber ;
       private boolean finished ;
       private java.math.BigDecimal grossWeight ;
       private java.math.BigDecimal netWeight ;
       private java.math.BigDecimal sizeLength ;
       private java.math.BigDecimal sizeWidth ;
       private java.math.BigDecimal sizeHeight ;
       private java.lang.String productRequest ;
       private java.math.BigDecimal price ;
       private java.math.BigDecimal amount ;
       private java.lang.String cunit ;
       private java.lang.Integer boxNum ;
       private java.math.BigDecimal exPrice ;
       private java.lang.String exUnit ;
       private java.math.BigDecimal noTax ;
       private java.math.BigDecimal tax ;
       private java.math.BigDecimal costPrice ;
       private java.math.BigDecimal costTax ;
       private java.lang.Integer orderNo ;
       private boolean accessories ;
       ......
    

    }

    ExtEproduct.java
    public class ExtCproduct {

       private Factory factory ;
       private ContractProduct contractProduct ;
      
       private java.lang.String id ;
       private java.lang.Integer ctype ;
       private java.lang.String typeName ;
       private java.lang.String productName ;
       private java.lang.String productNo ;
       private java.lang.String productImage ;
       private java.lang.String productDesc ;
       private java.lang.String loadingRate ;
      
       private java.lang.String packingUnit ;
       private java.lang.Integer cnumber ;
       private java.lang.Integer outNumber ;
       private boolean finished ;
       private java.math.BigDecimal grossWeight ;
       private java.math.BigDecimal netWeight ;
       private java.math.BigDecimal sizeLength ;
       private java.math.BigDecimal sizeWidth ;
       private java.math.BigDecimal sizeHeight ;
       private java.lang.String productRequest ;
       private java.math.BigDecimal price ;
       private java.math.BigDecimal amount ;
       private java.lang.String cunit ;
       private java.lang.Integer boxNum ;
       private java.math.BigDecimal exPrice ;
       private java.lang.String exUnit ;
       private java.math.BigDecimal noTax ;
       private java.math.BigDecimal tax ;
       private java.math.BigDecimal costPrice ;
       private java.math.BigDecimal costTax ;
       private java.lang.Integer orderNo ;
       private boolean accessories ;
       ......
    

    }

    6、创建映射文件(Export.hbm.xml、ExportProduct.hbm.xml和ExtEproduct.hbm.xml)
    Export.hbm.xml

    <?xml version="1.0" ?>
             <id name="id" type="string" column="EXPORT_ID" length="40">
                   <generator class="uuid" />
             </id>
            
             <property name="contractIds" column="CONTRACT_IDS" type="string" />
             <property name="customerContract" column="CUSTOMER_CONTRACT" type="string" />
    
             <property name="inputDate" column="INPUT_DATE" type="timestamp" />
             <property name="consignee" column="CONSIGNEE" type="string" />
             <property name="lcno" column="LCNO" type="string" />
             <property name="marks" column="MARKS" type="string" />
             <property name="shipmentPort" column="SHIPMENT_PORT" type="string" />
             <property name="destinationPort" column="DESTINATION_PORT" type="string" />
             <property name="transportMode" column="TRANSPORT_MODE" type="string" />
             <property name="priceCondition" column="PRICE_CONDITION" type="string" />
             <property name="remark" column="REMARK" type="string" />
    
             <property name="boxNum" column="BOX_NUM" type="integer" />
             <property name="cnumber" column="CNUMBER" type="integer" />
             <property name="packingUnit" column="PACKING_UNIT" type="string" />
            
             <property name="grossWeight" column="GROSS_WEIGHT" type="big_decimal" />
             <property name="netWeight" column="NET_WEIGHT" type="big_decimal" />
    
             <property name="sizeLength" column="SIZE_LENGTH" type="big_decimal" />
             <property name="sizeWidth" column="SIZE_WIDTH" type="big_decimal" />
             <property name="sizeHeight" column="SIZE_HEIGHT" type="big_decimal" />
             <property name="csize" column="CSIZE" type="big_decimal" />
    
             <property name="amount" column="AMOUNT" type="big_decimal" />          
             <property name="noTax" column="NO_TAX" type="big_decimal" />
             <property name="tax" column="TAX" type="big_decimal" />
             <property name="costPrice" column="COST_PRICE" type="big_decimal" />
             <property name="costTax" column="COST_TAX" type="big_decimal" />
            
             <property name="state" column="STATE" type="integer" />
            
        <property name="createBy" column="CREATE_BY" type="string" />
        <property name="createDept" column="CREATE_DEPT" type="string" />
             <property name="createTime" column="CREATE_TIME" type="timestamp" />
    
             <!-- Associations -->
    
             <set name="exportProduct" inverse="true" cascade="all" lazy="false" order-by= "ORDER_NO">
                   <key>
                         <column name="EXPORT_ID" />
                   </key>
                   <one-to-many class="cn.itcast.entity.ExportProduct" />
             </set>       
            
             <!-- one-to-one name="packingList" class="cn.itcast.entity.PackingList" lazy="false"  cascade="all"/-->
       </class>
    

    ExportProduct.hbm.xml

    <?xml version="1.0" ?>
             <id name="id" type="string" column="EXPORT_PRODUCT_ID" length="40" >
                   <generator class="uuid" />
             </id>
            
             <property name="contractProductId" column="CONTRACT_PRODUCT_ID" type="string" />
             <property name="contractId" column="CONTRACT_ID" type="string" />
             <property name="contractNo" column="CONTRACT_NO" type="string" />
            
             <property name="productName" column="PRODUCT_NAME" type="string" />
             <property name="productNo" column="PRODUCT_NO" type="string" />
             <property name="productImage" column="PRODUCT_IMAGE" type="string" />
             <property name="productDesc" column="PRODUCT_DESC" type="string" />
             <property name="loadingRate" column="LOADING_RATE" type="string" />
            
             <property name="packingUnit" column="PACKING_UNIT" type="string" />
             <property name="cnumber" column="CNUMBER" type="integer" />
             <property name="outNumber" column="OUT_NUMBER" type="integer" />
             <property name="finished" type="boolean" column="FINISHED" />
            
             <property name="grossWeight" column="GROSS_WEIGHT" type="big_decimal" />
             <property name="netWeight" column="NET_WEIGHT" type="big_decimal" />
            
             <property name="sizeLength" column="SIZE_LENGTH" type="big_decimal" />
             <property name="sizeWidth" column="SIZE_WIDTH" type="big_decimal" />
             <property name="sizeHeight" column="SIZE_HEIGHT" type="big_decimal" />
            
             <property name="productRequest" column="PRODUCT_REQUEST" type="string" />
             <property name="price" column="PRICE" type="big_decimal" />
             <property name="amount" column="AMOUNT" type="big_decimal" />
            
             <property name="cunit" column="CUNIT" type="string" />
             <property name="boxNum" column="BOX_NUM" type="integer" />
             <property name="exPrice" column="EX_PRICE" type="big_decimal" />
             <property name="exUnit" column="EX_UNIT" type="string" />
             <property name="noTax" column="NO_TAX" type="big_decimal" />
             <property name="tax" column="TAX" type="big_decimal" />
             <property name="costPrice" column="COST_PRICE" type="big_decimal" />
             <property name="costTax" column="COST_TAX" type="big_decimal" />
             <property name="orderNo" column="ORDER_NO" type="integer" />
            
             <property name="accessories" type="boolean" column="ACCESSORIES" />
            
             <!-- Associations -->
             <many-to-one name="factory" lazy="false" class="cn.itcast.entity.Factory" >
                   <column name="FACTORY_ID" length="40" />
             </many-to-one>
             <many-to-one name="export" lazy="false" class="cn.itcast.entity.Export" >
                   <column name="EXPORT_ID" length="40" />
             </many-to-one>
    
             <set name="extEproduct" inverse="true" cascade="all" lazy="false" order-by= "ORDER_NO">
                   <key>
                         <column name="EXPORT_PRODUCT_ID" />
                   </key>
                   <one-to-many class="cn.itcast.entity.ExtEproduct" />
             </set>
       </class>
    

    ExtEproduct.hbm.xml

    <?xml version="1.0" ?>
             <id name="id" type="string" column="EXT_EPRODUCT_ID" length="40" >
                   <generator class="uuid" />
             </id>
            
             <property name="ctype" column="CTYPE" type="integer" />
             <property name="typeName" type="string" formula="(select c.NAME from SYS_CODE_B c where c.ORDER_NO=CTYPE and c.PARENT_ID='0104')" insert="false" update="false"  />
    
             <property name="productName" column="PRODUCT_NAME" type="string" />
             <property name="productNo" column="PRODUCT_NO" type="string" />
             <property name="productImage" column="PRODUCT_IMAGE" type="string" />
             <property name="productDesc" column="PRODUCT_DESC" type="string" />
             <property name="loadingRate" column="LOADING_RATE" type="string" />
            
             <property name="packingUnit" column="PACKING_UNIT" type="string" />
             <property name="cnumber" column="CNUMBER" type="integer" />
             <property name="outNumber" column="OUT_NUMBER" type="integer" />
             <property name="finished" type="boolean" column="FINISHED" />
            
             <property name="grossWeight" column="GROSS_WEIGHT" type="big_decimal" />
             <property name="netWeight" column="NET_WEIGHT" type="big_decimal" />
            
             <property name="sizeLength" column="SIZE_LENGTH" type="big_decimal" />
             <property name="sizeWidth" column="SIZE_WIDTH" type="big_decimal" />
             <property name="sizeHeight" column="SIZE_HEIGHT" type="big_decimal" />
            
             <property name="productRequest" column="PRODUCT_REQUEST" type="string" />
             <property name="price" column="PRICE" type="big_decimal" />
             <property name="amount" column="AMOUNT" type="big_decimal" />
            
             <property name="cunit" column="CUNIT" type="string" />
             <property name="boxNum" column="BOX_NUM" type="integer" />
             <property name="exPrice" column="EX_PRICE" type="big_decimal" />
             <property name="exUnit" column="EX_UNIT" type="string" />
             <property name="noTax" column="NO_TAX" type="big_decimal" />
             <property name="tax" column="TAX" type="big_decimal" />
             <property name="costPrice" column="COST_PRICE" type="big_decimal" />
             <property name="costTax" column="COST_TAX" type="big_decimal" />
             <property name="orderNo" column="ORDER_NO" type="integer" />
            
             <property name="accessories" type="boolean" column="ACCESSORIES" />
            
             <!-- Associations -->
             <many-to-one name="factory" lazy="false" class="cn.itcast.entity.Factory" >
                   <column name="FACTORY_ID" length="40" />
             </many-to-one>
             <many-to-one name="exportProduct" cascade="all" lazy="false" class="cn.itcast.entity.ExportProduct" >
                   <column name="EXPORT_PRODUCT_ID" length="40" />
             </many-to-one>     
    
       </class>
    

    7、创建DAO(ExportDAO.java、ExportProductDAO.java和ExtEproductDAO.java)
    ExportDAO.java
    public class ExportDAO extends _RootDAO {

    }

    ExportProductDAO.java
    public class ExportProductDAO extends _RootDAO {

    }

    ExtEproductDAO.java
    public class ExtEproductDAO extends _RootDAO {

    }

    8、声明(beans.xml、hibernate.cfg.xml)
    beans.xml

    hibernate.cfg.xml

    9、创建Action(ExportAction.java)
    ExportAction.java
    public class ExportAction extends _BaseStruts2Action implements ModelDriven {
    private Export model = new Export();
    public Export getModel() {
    return model ;
    }

       //列表
       public String list(){
            ExportDAO oDao = (ExportDAO) this.getDao("daoExport" );
            List<Export> dataList = oDao.find("from Export o");
            ActionContext. getContext().put("dataList", dataList);
            
             return "plist" ;
      }
      
       //保存
       public String exportsave(){
             /*
             * 操作步骤:
             * 1、获得多个合同信息
             * 2、获得合同下的货物信息和附件信息,保存到当前报运下的货物、附件信息。
             *
             */
             //1、获得多个合同信息,新建报运
            String[] ids = model.getId().split(", " );       //contract id
            
            String _tempstr = "";
            ExportDAO oDao = (ExportDAO) this.getDao("daoExport" );
            Export export = new Export();
            export.setContractIds( model.getId().replace(" " , "" ));             //contract id
            
            ContractDAO cDao = (ContractDAO) this.getDao("daoContract" );
             for(int i=0;i<ids.length;i++){
                  Contract contract = (Contract) cDao.get(Contract.class , ids[i]);
                  _tempstr += contract.getContractNo()  + " ";
            }
            export.setCustomerContract(_tempstr);
            
             //获取货物信息
            Set<ExportProduct> epSet = new HashSet();
            Set<ExtEproduct> extepSet = new HashSet();
            ExportProduct ep = null;
            ExtEproduct extep = null;
            
            List<ContractProduct> cpList = cDao.find("from ContractProduct o where o.contract.id in ('" + model.getId().replace(", ", "','") + "')");                   // 'x','y','z'
             for(ContractProduct cp: cpList){
                  ep = new ExportProduct();
                  ep.setAccessories(cp.isAccessories());
                  ep.setProductNo(cp.getProductNo());
                  ep.setProductDesc(cp.getProductDesc());
                  ep.setCnumber(cp.getCnumber());
                  ep.setPrice(cp.getPrice());
                  ep.setAmount(cp.getAmount());
                  
                  ep.setExport(export);                //绑定关联关系
                  
                   //货物附件信息
                   for(ExtCproduct extcp: cp.getExtCproduct()){
                        extep = new ExtEproduct();
                        extep.setProductNo(extcp.getProductNo());
                        extep.setProductDesc(extcp.getProductDesc());
                        extep.setCnumber(extcp.getCnumber());
                        extep.setPrice(extcp.getPrice());
                        extep.setAmount(extcp.getAmount());
                        
                        extep.setExportProduct(ep);    //绑定关联关系
                        
                        extepSet.add(extep);
                  }
                  ep.setExtEproduct(extepSet);   //绑定关联关系
                   
                  epSet.add(ep);
            }
            export.setExportProduct(epSet);            //绑定关联关系
             
            oDao.saveOrUpdate(export);
            
             return list();
      }
      
       //转向查看页面
       public String toview(){
            ExportDAO oDao = (ExportDAO) this.getDao("daoExport" );
            Export obj = (Export) oDao.get(Export. class, model .getId());
            ActionContext. getContext().getValueStack().push(obj);
            
             return "pview" ;
      }
      
       //删除
       public String delete(){
            String[] ids = model.getId().split(", " );
            ExportDAO oDao = (ExportDAO) this.getDao("daoExport" );
            oDao.deleteAllById(ids, Export. class);
            
             return list();
      }
      
       //上报      0草稿 1已上报待装箱
       public String submit(){
             this.chstate(1);
             return list();
      }
      
       //取消      0草稿 1已上报待装箱
       public String cancelsubmit(){
             this.chstate(0);
             return list();
      }
      
       //修改状态 1正常0停用
       private void chstate(Integer value){
            String[] ids = model.getId().split(", " );       //注意分隔符
            Export export = null;
             Set oSet = new HashSet();
            ExportDAO oDao = (ExportDAO) this.getDao("daoExport" );
             for(int i=0;i<ids.length;i++){
                  export = (Export) oDao.get(Export. class, ids[i]);
                  export.setState(value);
                  
                   oSet.add(export);
            }
            oDao.saveOrUpdateAll(oSet);                //批量保存
      }     
    

    }

    10、struts配置
    struts-cargo.xml


    /cargo/export/jExportView.jsp</ result>
    /cargo/export/jExportList.jsp</ result>
    /cargo/export/jExportCreate.jsp</ result>
    /cargo/export/jExportUpdate.jsp</ result>

    11、创建JSP页面(其他页面见源码)
    jContractList.jsp
    < li id =“back”>报运</ a>
    left.jsp
    < li>
    报运管理

    12、测试
    测试报运功能

    测试查看操作

    测试修改操作

    测试删除操作

    12 出口报运(2)
    13、报运批量修改实现(重点代码,全码见源码)
    jExportUpdate.jsp

    序号 货号 数量 毛重 净重

    tabledo.js
    /* 设置此行是否更新 by tony 20091110
    */
    function setTRUpdateFlag( obj ){
    var currTr = obj.parentElement.parentElement;
    if (currTr.innerHTML.toLowerCase().indexOf( “<span”)==0){
    currTr = obj.parentElement.parentElement.parentElement;
    }
    if (obj.value!=obj.defaultValue){ //当填写的框内容发生变化时,设置本行记录发生变化标识
    currTr.cells[1].all.mr_changed.value = “1” ;
    }
    }

    ExportAction.java
    //转入修改页面
    public String toupdate(){
    ExportDAO oDao = (ExportDAO) this.getDao(“daoExport” );
    Export obj = (Export) oDao.get( Export.class, model.getId());
    ActionContext. getContext().getValueStack().push(obj);

       //拼接html片段    addTRRecord(objId, id, productNo, cnumber, grossWeight, netWeight)
      StringBuffer sBuf = new StringBuffer();
      
       for(ExportProduct ep: obj.getExportProduct()){
            sBuf.append( "addTRRecord(\"resultTable\", \"").append(ep.getId()).append( "\",")
            .append( "\"").append(ep.getProductNo()).append("\", " )
            .append( "\"").append(ep.getCnumber()).append("\", " )
            .append( "\"").append(UtilFuns.convertNull(ep.getGrossWeight())).append( "\", ")
            .append( "\"").append(UtilFuns.convertNull(ep.getNetWeight())).append( "\"")
            .append( ");");
      }
      
      ActionContext. getContext().put("mrecordData", sBuf.toString());
      
       return "pupdate" ;
    

    }

    //修改
    public String save(){
    ExportDAO oDao = (ExportDAO) this.getDao(“daoExport” );
    HttpServletRequest request = ServletActionContext. getRequest();

      String[] mr_id = request.getParameterValues( "mr_id");
      String[] orderNo = request.getParameterValues( "orderNo");
      String[] mrChanged = request.getParameterValues( "mr_changed");            //为1表示修改,否则未修改
      
      String[] productNo = request.getParameterValues( "ep_productNo");
      String[] cnumber = request.getParameterValues( "ep_cnumber");
      String[] grossWeight = request.getParameterValues("ep_grossWeight" );
      String[] netWeight = request.getParameterValues( "ep_netWeight");
      
      Set<ExportProduct> epSet = new HashSet();
      ExportProductDAO epDao = (ExportProductDAO) this.getDao("daoExportProduct" );
      ExportProduct ep = null;
       for(int i =0 ;i<orderNo.length;i++){
            
             //优化,跳过无需修改的记录
             if(mrChanged[i].compareTo("1" )!=0){
                   continue;
            }
            ep = (ExportProduct) epDao.get(ExportProduct. class, mr_id[i]);
            
            ep.setProductNo(productNo[i]);
             if(UtilFuns.isNotEmpty(cnumber[i])){
                  ep.setCnumber(Integer. parseInt(cnumber[i]));
            }
             if(UtilFuns.isNotEmpty(grossWeight[i])){
                  ep.setGrossWeight( new BigDecimal(grossWeight[i]));
            }
             if(UtilFuns.isNotEmpty(netWeight[i])){
                  ep.setNetWeight( new BigDecimal(netWeight[i]));
            }
            
             if(UtilFuns.isNotEmpty(orderNo[i])){
                  ep.setOrderNo(Integer. parseInt(orderNo[i]));
            }
            epSet.add(ep);
      }
       model.setExportProduct(epSet);
      
      oDao.saveOrUpdate( model);
      
       return list();
    

    }

    附:
    ①实现思路
    选择某个合同,点击修改按钮,就会调用ExportAction中的toupdate方法。toupdate方法中拼接了一段html片段,并将其放在域中。此片段功能是调用jExportUpdate.jsp中的JS脚本中的addTRRecord方法,从而插入数据。如果数据有任何的修改,就会调用setTRUpdateFlag方法将id为mr_changed的隐藏域值变为1,从而在点击保存按钮后,调用ExportAction中的save方法,将数据库中的相应记录修改掉。
    ②分次走货,一个合同,可能多次报运。

    测试修改

    14、打印出口商品报运单
    首先插入出口报运表、货物以及附件的测试数据。

    出口商品报运单模板

    ExportAction.java
    //打印
    public void print() throws IOException, ParseException{
    ExportPrint eprint = new ExportPrint();
    ExportDAO oDao = (ExportDAO) this.getDao(“daoExport” );
    HttpServletResponse response = ServletActionContext. getResponse();
    eprint.print( model.getId(), oDao, response);
    }

    ExportPrint.java(重点功能和重点代码)
    ①复制工作簿 wb.cloneSheet(工作簿的序号);
    附:

    由于出口商品报运单包含多个样式相同的工作簿,所以需要拷贝工作簿。

    ②动态计算工作簿个数
    Arith arith = new Arith();
    sheetCount = arith.round(obj.getExportProduct().size(), rowCount); //sheet num

    ③输出货物信息时,定位其所在工作簿
    int rowCount = 11; //每个sheet的子记录数
    int rnum = 0; //当前行数
    int pnum = -1; //当前页数

    pnum = rnum/rowCount;
    sheet = wb.getSheetAt(pnum); //选择第n个工作簿 动态切换工作簿

    ④最后一个工作簿进行合计
    1)访问前面的工作簿 工作簿名称!..
    2)SUMPRODUCT(…) 参数相乘,然后累加
    //拼接公式串
    bufGrossWeight.append(“SUM(”);
    bufNetWeight.append(“SUM(”);
    bufSize.append(“SUM(”);
    for(int j=0;j<sheetCount;j++){
    if(j==0){
    bufGrossWeight.append( “SUMPRODUCT(报运单!I” ).append(rowStart).append(“:I”).append(rowStop).append( “,报运单!H” ).append(rowStart).append(“:H”).append(rowStop).append( “),”);
    bufNetWeight.append( “SUMPRODUCT(报运单!J” ).append(rowStart).append(“:J”).append(rowStop).append( “,报运单!H” ).append(rowStart).append(“:H”).append(rowStop).append( “),”);
    bufSize.append( “SUMPRODUCT(报运单!K” ).append(rowStart).append(“:K”).append(rowStop).append( “,报运单!L” ).append(rowStart).append(“:L”).append(rowStop).append( “,报运单!M” ).append(rowStart).append(“:M”).append(rowStop).append( “,报运单!H” ).append(rowStart).append(“:H”).append(rowStop).append( “)/100/100/100,”);
    } else{
    wb.cloneSheet(0); //复制sheet0工作簿,名字会自动重命名

            bufGrossWeight.append( "SUMPRODUCT('报运单(" ).append(j).append(")'!I").append(rowStart).append( ":I").append(rowStop).append(",'报运单(" ).append(j).append(")'!H").append(rowStart).append( ":H").append(rowStop).append(")," );
            bufNetWeight.append( "SUMPRODUCT('报运单(" ).append(j).append(")'!J").append(rowStart).append( ":J").append(rowStop).append(",'报运单(" ).append(j).append(")'!H").append(rowStart).append( ":H").append(rowStop).append(")," );
            bufSize.append( "SUMPRODUCT('报运单(" ).append(j).append(")'!K").append(rowStart).append( ":K").append(rowStop).append(",'报运单(" ).append(j).append(")'!L").append(rowStart).append( ":L").append(rowStop).append(",'报运单(" ).append(j).append(")'!M").append(rowStart).append( ":M").append(rowStop).append(",'报运单(" ).append(j).append(")'!H").append(rowStart).append( ":H").append(rowStop).append(")/100/100/100," );
      }
    

    }

    测试

    13 装箱
    1、业务逻辑
    装箱就是计划将货物装到集装箱中进行运输。
    根据多个出口报运单制定装箱单,填写发票号、发票时间,以及客人等相关信息。
    装箱关注主货物,不关心附件。及其最终的总箱数、毛重、净重、体积。

    2、功能描述及其分析

    3、技术要点

    4、数据库表设计&执行SQL

    附:
    由表结构可以看到装箱单与报运单之间是一对多的关系,这里通过在装箱单表中设置特定字段从而保存与其相关的报运单号。

    5、创建PO对象及映射文件(PackingList.java及PackingList.hbm.xml)
    PackingList.java
    public class PackingList {
    private java.lang.String id ;
    private java.lang.String seller ;
    private java.lang.String buyer ;
    private java.lang.String invoiceNo ;
    private java.util.Date invoiceDate ;
    private java.lang.String marks ;
    private java.lang.String descriptions ;
    private java.lang.String exportIds ;
    private java.lang.String exportNos ;
    private java.lang.String createBy ;
    private java.lang.String createDept ;
    private java.util.Date createTime ;

    }

    PackingList.hbm.xml

    <?xml version="1.0" ?>
             <id name="id" type="string" column="PACKING_LIST_ID" length="40" >
                   <generator class="uuid" />
             </id>
            
             <property name="seller" column="SELLER" type="string" />
             <property name="buyer" column="BUYER" type="string" />
             <property name="invoiceNo" column="INVOICE_NO" type="string" />
             <property name="invoiceDate" column="INVOICE_DATE" type="timestamp" />
             <property name="marks" column="MARKS" type="string" />
             <property name="descriptions" column="DESCRIPTIONS" type="string" />
            
             <property name="exportIds" column="EXPORT_IDS" type="string" />
             <property name="exportNos" column="EXPORT_NOS" type="string" />
            
             <property name="createBy" column="CREATE_BY" type="string" />
             <property name="createDept" column="CREATE_DEPT" type="string" />
             <property name="createTime" column="CREATE_TIME" type="timestamp" />
    
       </class>
    

    6、创建DAO(PackingListDAO.java)
    public class PackingListDAO extends _RootDAO {

    }

    7、声明(beans.xml、hibernate.cfg.xml)
    beans.xml

    hibernate.cfg.xml

    8、创建Action(PackingListAction.java)
    PackingListAction.java
    public class PackingListAction extends _BaseStruts2Action implements ModelDriven {
    private PackingList model = new PackingList();
    public PackingList getModel() {
    return model ;
    }

       //列表
       public String list(){
            PackingListDAO oDao = (PackingListDAO) this.getDao("daoPackingList" );
            List<PackingList> dataList = oDao.find("from PackingList o");
            ActionContext. getContext().put("dataList", dataList);
            
            return "plist" ;
      }
      
       //新增
       public String tocreate(){
             /*
             * 1、获取多个报运的ID
             * 2、拼接HTML代码片段
             * */
            String[] exportIds = model.getId().split(", " );              //报运号
            StringBuffer sBuf = new StringBuffer();
            
            ExportDAO eDao = (ExportDAO) this.getDao("daoExport" );
            Export export = null;
            
             for(int i=0;i<exportIds.length;i++){
                  export = (Export) eDao.get(Export. class, exportIds[i]);
                  
                  sBuf.append( "<input type=\"checkbox\" name=\"exportId\" checked=\"true\"  value=\"").append(exportIds[i]).append( "|").append(export.getCustomerContract()).append("\" class=\"input\"/>");
                  sBuf.append(export.getCustomerContract());
                  sBuf.append( "&nbsp;&nbsp;");
            }
            ActionContext. getContext().put("mrecordData", sBuf.toString());
            
            return "pcreate" ;
      }
      
       //转向修改页面
       public String toupdate(){
            PackingListDAO oDao = (PackingListDAO) this.getDao("daoPackingList" );
            PackingList obj = (PackingList) oDao.get(PackingList. class, model.getId());
            ActionContext. getContext().getValueStack().push(obj);
            
             //准备数据,拼接HTML片段
            StringBuffer sBuf = new StringBuffer();
            String[] _exportIds = obj.getExportIds().split( "\\|");
            String[] _exportNos = obj.getExportNos().split( "\\|");
            
             for(int i=0;i<_exportIds.length;i++){
                  sBuf.append( "<input type=\"checkbox\" name=\"exportId\" checked=\"true\"  value=\"").append(_exportIds[i]).append( "|").append(_exportNos[i]).append("\" class=\"input\"/>" );
                  sBuf.append(_exportNos[i]);
                  sBuf.append( "&nbsp;&nbsp;");
            }
            ActionContext. getContext().put("mrecordData", sBuf.toString());
            
            return "pupdate" ;
      }
    
       //新增保存
       public String createSave(){
            PackingListDAO oDao = (PackingListDAO) this.getDao("daoPackingList" );
            String[] _tempstr = null;
            
            HttpServletRequest request = ServletActionContext.getRequest();
            String _exportIds = "";
            String _exportNos = "";
            String[] exportId = request.getParameterValues( "exportId");                   //报运ID+报运号
             for(int i=0;i<exportId.length;i++){
                  _tempstr = exportId[i].split( "\\|");                   //注意参数为正则表达式
                  _exportIds += _tempstr[0] + "|";
                  _exportNos += _tempstr[1] + "|";
            }
            _exportIds = UtilFuns. DelLastChar(_exportIds);
            _exportNos = UtilFuns. DelLastChar(_exportNos);
            
             model.setExportIds(_exportIds);
             model.setExportNos(_exportNos);
            
            oDao.saveOrUpdate( model);
            
             //获得新增的装箱对应的多个报运
            Set<Export> eSet = new HashSet();
            ExportDAO eDao = (ExportDAO) this.getDao("daoExport" );
            List<Export> oList = eDao.find("from Export o where o.id in ('"+_exportIds.replace( "|", "','")+"')") ;
             for(Export export: oList){
                  export.setState(2);                  //0-草稿 1-已上报 2-装箱 3-委托 4-发票 5-财务
                  
                  eSet.add(export);
            }
            eDao.saveOrUpdateAll(eSet);
            
            return list();
      }
      
       //保存
       public String save(){
            PackingListDAO oDao = (PackingListDAO) this.getDao("daoPackingList" );
            String[] _tempstr = null;
            
            HttpServletRequest request = ServletActionContext.getRequest();
            String _exportIds = "";
            String _exportNos = "";
            String[] exportId = request.getParameterValues( "exportId");                   //报运ID+报运号
             for(int i=0;i<exportId.length;i++){
                  _tempstr = exportId[i].split( "\\|");                   //注意参数为正则表达式
                  _exportIds += _tempstr[0] + "|";
                  _exportNos += _tempstr[1] + "|";
            }
            _exportIds = UtilFuns. DelLastChar(_exportIds);
            _exportNos = UtilFuns. DelLastChar(_exportNos);
            
             model.setExportIds(_exportIds);
             model.setExportNos(_exportNos);
            
            oDao.saveOrUpdate( model);
    
            return list();
      }     
      
       //转向查看页面
       public String toview(){
            PackingListDAO oDao = (PackingListDAO) this.getDao("daoPackingList" );
            PackingList obj = (PackingList) oDao.get(PackingList. class, model.getId());
            ActionContext. getContext().getValueStack().push(obj);
            
             //准备数据,拼接HTML片段
            StringBuffer sBuf = new StringBuffer();
            String[] _exportIds = obj.getExportIds().split( "\\|");
            String[] _exportNos = obj.getExportNos().split( "\\|");
            
             for(int i=0;i<_exportIds.length;i++){
                  
                  sBuf.append( "<a href=\"/export/exportAction_toviewinfo?id=").append(_exportIds[i]).append( "\">");
                  sBuf.append(_exportNos[i]);
                  sBuf.append( "</a>");
                  sBuf.append( "&nbsp;&nbsp;");
            }
            ActionContext. getContext().put("mrecordData", sBuf.toString());
            
            return "pview" ;
      }
      
       //删除
       public String delete(){
            String[] ids = model.getId().split(", " );
            PackingListDAO oDao = (PackingListDAO) this.getDao("daoPackingList" );
            oDao.deleteAllById(ids, PackingList. class);
            
            return list();
      }     
      
       //打印
       public void print() throws Exception{
            HttpServletRequest request = ServletActionContext.getRequest();
            HttpServletResponse response = ServletActionContext.getResponse();
            PackingListDAO oDao = (PackingListDAO) this.getDao("daoPackingList" );
            ExportDAO eDao = (ExportDAO) this.getDao("daoExport" );
            
            PackingListPrint packingListPrint = new PackingListPrint();
            packingListPrint.print(request, response, oDao, eDao);
      }
    

    }
    附:
    PackingListAction中的tocreate、toupdate、toview方法中都将与某装箱单相关的报运单号组织成html片段存储在request域中,以便在页面中展示出来。
    需要指出的是toview方法中组织html片段的时候,为每个报运单合同号添加了超链接,从而可以通过点击报运单号就可以看到其包含的货物及附件。

    附:修改报运单状态信息
    PackingListAction.java
    //新增保存
    public String createSave(){

       //获得新增的装箱对应的多个报运
      Set<Export> eSet = new HashSet();
      ExportDAO eDao = (ExportDAO) this .getDao("daoExport" );
      List<Export> oList = eDao.find( "from Export o where o.id in ('"+_exportIds.replace( "|" , "','")+ "')") ;
       for (Export export: oList){
            export.setState(2);                  //0-草稿 1-已上报 2-装箱 3-委托 4-发票 5-财务
            
            eSet.add(export);
      }
      eDao.saveOrUpdateAll(eSet);
      
       return list();
    

    }
    由于客户经常询问单子的状态信息,所以在报运中需要实时更新。

    9、struts配置
    struts-cargo.xml


    /cargo/packinglist/jPackingListView.jsp
    /cargo/packinglist/jPackingListList.jsp
    /cargo/packinglist/jPackingListCreate.jsp
    /cargo/packinglist/jPackingListUpdate.jsp

    10、创建JSP页面(其他页面见源码)
    jExportList.jsp
    < li id =“new”>装箱</ a>
    left.jsp
    < li>
    装箱管理
    jPackingListCreate.jsp
    < div class =“listTablew” >
    < div id= “contractList” style = “float:left;margin:8px;”>
    ${mrecordData}
    </ div>
    </ div>
    jPackingListUpdate.jsp

    ${mrecordData}
    jPackingListView.jsp
    ${mrecordData}

    11、测试
    测试装箱

    测试查看

    测试修改

    测试删除

    12、打印装箱单
    由于使用POI打印装箱单并没有用到什么新的技巧,所以这里省略。否则,阅读起来也是浪费读者的时间。

    13、通过自定义标签打印唛头
    附:
    主要将数据库中的唛头信息中的空格换成html的&nbsp,换行换成
    ,从而在页面上正常展示。

    jExportInfo.jsp

    唛头: ${selffn:htmlNewline(marks)}

    selffn.tld

    htmlNewline
    cn.itcast.web.common.util.UtilFuns
    java.lang.String htmlNewline(java.lang.String)</ function-signature>

    UtilFuns.java
    public static String htmlNewline(String s){
    try{
    //如不替换空格, html解释时会自动把多个空格显示为一个空格,这样当我们通过空格来布局时就出现 textarea中和html页面展现不一致的情况 tony
    //s.replaceAll(" “,” “) 不能进行空格的替换,否则页面内容中如果有<img src=“xxx.jpg” >等标签,内容就会显示乱;<img  src=“xxx.jpg"nbsp;>
    return s.replaceAll(” “,” “).replaceAll( “\n”,”<br\>” );
    } catch(Exception e){
    return “” ;
    }
    }
    14 委托
    1、业务逻辑
    需要将货物送到客户指定的地方,可能直接送到港口,可能送到客户的门店。因为贸易公司很小,几十号人,不可能有自己的车队,即使有车队,也基本上不会有船、飞机,通常都是委托其他运输公司来运输。这就是委托。
    委托关注的是包装后的货物占用空间总大小,以确定集装箱的大小和个数。自此已经不关心货物的详细情况。
    根据装箱单来制定委托书。一个装箱单对一个委托书。

    2、功能描述及其分析

    3、技术要点

    4、数据库表设计&执行SQL

    5、创建PO对象及映射文件(ShippingOrder.java及ShippingOrder.hbm.xml)
    ShippingOrder.java
    public class ShippingOrder {
    private java.lang.String id ;
    private java.lang.String orderType ;
    private java.lang.String shipper ;
    private java.lang.String consignee ;
    private java.lang.String notifyParty ;
    private java.lang.String lcno ;
    private java.lang.String portOfLoading ;
    private java.lang.String portOfTrans ;
    private java.lang.String portOfDischarge ;
    private java.util.Date loadingDate ;
    private java.util.Date limitDate ;
    private java.lang.String isBatch ;
    private java.lang.String isTrans ;
    private java.lang.String copyNum ;
    private java.lang.String cnote ;
    private java.lang.String specialCondition ;
    private java.lang.String freight ;
    private java.lang.String checkBy ;
    private java.lang.String createBy ;
    private java.lang.String createDept ;
    private java.util.Date createTime ;
    private PackingList packingList ;

    }

    ShippingOrder.hbm.xml

    <?xml version="1.0" ?>
            <id name="id" type="string" column="SHIPPING_ORDER_ID" length="40" >
                   <generator class="assigned" />
             </id>
            
             <property name="orderType" column="ORDER_TYPE" type="string" />
             <property name="shipper" column="SHIPPER" type="string" />
             <property name="consignee" column="CONSIGNEE" type="string" />
             <property name="notifyParty" column="NOTIFY_PARTY" type="string" />
             <property name="lcno" column="LC_NO" type="string" />
             <property name="portOfLoading" column="PORT_OF_LOADING" type="string" />
             <property name="portOfTrans" column="PORT_OF_TRANS" type="string" />
             <property name="portOfDischarge" column="PORT_OF_DISCHARGE" type="string" />
             <property name="loadingDate" column="LOADING_DATE" type="timestamp" />
             <property name="limitDate" column="LIMIT_DATE" type="timestamp" />
             <property name="isBatch" column="IS_BATCH" type="string" />
             <property name="isTrans" column="IS_TRANS" type="string" />
             <property name="copyNum" column="COPY_NUM" type="string" />
             <property name="cnote" column="CNOTE" type="string" />
             <property name="specialCondition" column="SPECIAL_CONDITION" type="string" />
             <property name="freight" column="FREIGHT" type="string" />
             <property name="checkBy" column="CHECK_BY" type="string" />
            
             <property name="createBy" column="CREATE_BY" type="string" />
             <property name="createDept" column="CREATE_DEPT" type="string" />
             <property name="createTime" column="CREATE_TIME" type="timestamp" />
            
             <!-- Associations -->
            <one-to-one name="packingList" class="cn.itcast.entity.PackingList" lazy="false"/>
    
       </class>
    
    附:由于委托单和装箱单是一对一的关系,所以直接将装箱单的Id设置为委托单的Id,其赋值类型为assigned。

    PackingList.java
    public class PackingList {
    private ShippingOrder shippingOrder ;
    public ShippingOrder getShippingOrder() {
    return shippingOrder ;
    }
    public void setShippingOrder(ShippingOrder shippingOrder) {
    this.shippingOrder = shippingOrder;
    }

    }

    PackingList.hbm.xml
    < one-to-one name =“shippingOrder” class= “cn.itcast.entity.ShippingOrder” lazy =“false” cascade =“all”/>
    附:因为装箱是在报运之后执行的,所以删除报运单就要删除下面所属的所有装箱单,而装箱单删除却不会要求删除其对应的报运单。所以,报运单的一对一标签中设置了cascade属性,而装箱单中的一对一标签则没有设置。

    6、创建DAO(ShippingOrderDAO.java)
    public class ShippingOrderDAO extends _RootDAO {

    }

    7、声明(beans.xml、hibernate.cfg.xml)
    beans.xml

    hibernate.cfg.xml

    8、创建Action(ShippingOrderAction.java)
    ShippingOrderAction.java
    public class ShippingOrderAction extends _BaseStruts2Action implements ModelDriven{
    private String subid ;
    public String getSubid() {
    return subid ;
    }

       public void setSubid(String subid) {
             this.subid = subid;
      }
    
       private ShippingOrder model = new ShippingOrder();
       public ShippingOrder getModel() {
             return model ;
      }
    
       //转向编辑页面
       public String toedit(){
             //准备数据
            ShippingOrderDAO oDao = (ShippingOrderDAO) this.getDao("daoShippingOrder" );
            ShippingOrder obj = (ShippingOrder) oDao.get(ShippingOrder.class , model .getId());
            ActionContext. getContext().put("obj", obj);
            
             return "pedit" ;
      }
      
       //保存
       public String save(){
            ShippingOrderDAO oDao = (ShippingOrderDAO) this.getDao("daoShippingOrder" );
            oDao.saveOrUpdate( model);
            
             //新增
             if(UtilFuns.isEmpty( this.getSubid())){
                  PackingListDAO pDao = (PackingListDAO) this.getDao("daoPackingList" );
                  PackingList packingList = (PackingList) pDao.get(PackingList.class , model .getId());
                  
                   //获得新增的委托对应的多个报运
                  Set<Export> eSet = new HashSet();
                  ExportDAO eDao = (ExportDAO) this.getDao("daoExport" );
                  List<Export> oList = eDao.find("from Export o where o.id in ('"+packingList.getExportIds().replace( "|", "','")+"')") ;
                   for(Export export: oList){
                        export.setState(3);                  //0-草稿 1-已上报 2-装箱 3-委托 4-发票 5-财务
                        
                        eSet.add(export);
                  }
                  eDao.saveOrUpdateAll(eSet);
            }
             return toedit();
      }
    

    }

    9、struts配置
    struts-cargo.xml


    /cargo/shippingorder/jShippingOrderEdit.jsp

    10、创建JSP页面(其他页面见源码)
    jShippingOrderEdit.jsp
    <s:if test=“#request.obj==null” >新增</ s:if>
    <s:if test=“#request.obj.id!=null” >修改</ s:if>
    附:由于新增和修改使用的是同一个页面,所以应该根据id是否为null,来判断到底是新增还是修改。

    11、测试

    附:发票模块与委托模块非常相似,都是与其他表一对一的关系,所以这里省略。
    15 统一查询框架
    1、思路
    当用户请求执行ContractAction.java的list方法时,将搜索类别的显示内容以及值作为参数传递给UtilFuns.java的ComboList方法组装成html片段,存储在域中。在jContractList.jsp中,显示出列别。用户选择搜索的类别并且输入值,这些信息最终都会交给_RootDAO.java的dataList方法,从接拼接hql语句,并且查询出数据。然后放入map栈中,供jContractList.jsp显示。

    2、代码
    UtilFuns.java
    /** ComboList 功能:选定在下拉列表框中与查找到数据,相符的那一项内容


    • 输入参数:String CurrentValue 查找出的数据库中的数据
    •           String[] content 需要输出的所有下拉列表框的内容
      

    • 输出参数:返回下拉列表

    • 注意事项:values为0开始,而且中间不能断开
      */
      public String ComboList(String CurrentValue, String[] content) {
      int i = 0;
      StringBuffer sBuf = new StringBuffer();
      String selected = " selected";
      try{
      sBuf.append(“–请选择–” );
      for (i = 0; i < content. length; i++) {
      sBuf.append( “\n<option value='”).append(i).append(“'” );
      if (CurrentValue.compareTo(String. valueOf(i)) == 0) {
      sBuf.append(selected);
      }
      sBuf.append( “>”).append(content[i]).append(“” );
      }
      return sBuf.toString();
      }catch(Exception e){
      return “”;
      }
      }

    _RootDAO.java
    public class _RootDAO extends _BaseRootDAO{
    /*
    * 统一查询框架 by tony
    * who 哪个业务对象
    * pValue 下拉框的值 pText
    * pText 下拉框的文字
    * dlValue 下拉框选中的值
    * curValue 用户输入的查询值
    */
    public List dataList( String who, String [] pValue, String[] pText, String dlValue, String curValue){

            UtilFuns utilFuns = new UtilFuns();
             String[] aConditionStr = utilFuns.splitFindStr(curValue);             //规整分隔符,支持空格、逗号、中文件逗号
    
            StringBuffer hql = new StringBuffer();
            hql.append( "from ").append(who).append(" o where 1=1" );
            
             List paraList = new ArrayList();
             int j=0;j=0;
            
             //进行模糊查询,类似 google的处理
             if (UtilFuns.isNotEmpty(curValue)) {
                   for(int i=0;i<aConditionStr.length;i++){
                         if (UtilFuns.isNotEmpty(dlValue)) {
                              hql.append( " and o.").append(dlValue).append(" like ?");
                               paraList.add("%" + aConditionStr[i] + "%" );
                        } else{
                              hql.append( " and (");
                               for(j=0;j<pValue.length ;j++){
                                    hql.append( "o.").append(pValue[j]).append(" like ? or " );
                                     paraList.add("%" + aConditionStr[i] + "%" );
                              }
                              hql.delete(hql.length()-3, hql.length());       //del last ' or'
                              hql.append( ")");
                        }
                  }
            }
            
             return this .find(hql.toString(), paraList.toArray());        //返回查询结果
      }
            
       /*
       *
       * 取得单值,返回字符串,多个内容时形成一个字符串用逗号隔开
       * ex: hql   "select o.id from Contract o where ... "
       *  */
       public String findString( String hql) {
             String s = "";
             List aList = this.getHibernateTemplate().find(hql);
             if(aList!=null && aList.size()>0){
                   if(aList.size()==1){
                        s = ( String)aList.get(0);
                  } else{
                         for(int i=0;i<aList.size();i++){
                              s += ( String)aList.get(i) + ",";
                        }
                        UtilFuns utilFuns = new UtilFuns();
                        s = utilFuns.DelLastChar(s);
                  }
            }
             return s;
      }
    

    }

    BaseStruts2Action.java
    public class _BaseStruts2Action extends ActionSupport {

       //统一查询框架
       public String f_conditionStr ;              //用户输入的查询条件
       public String f_type ;                            //下拉框选择的当前值
       public String comboContentStr ;                   //下拉框option串
       ......
    

    }

    ContractAction.java
    public class ContractAction extends _BaseStruts2Action implements ModelDriven {
    private Contract model = new Contract();
    public Contract getModel() {
    return model ;
    }

       //列表
       public String list(){
            ContractDAO oDao = (ContractDAO) this.getDao("daoContract" );
            UtilFuns utilFuns = new UtilFuns();
            
            String[] pValue = {"contractNo" ,"customName" ,"inputBy" ,"inspector" };
            String[] pText = { "合同号","客户名称" ,"制单人" ,"验货员" };
            
             //传递到页面的查询参数
            comboContentStr = utilFuns.ComboList(f_type , pValue, pText);             //构造下拉框option
            ActionContext. getContext().put("dataList", oDao.dataList("Contract" , pValue, pText, f_type, f_conditionStr));
            
             return "plist" ;
    
      }
      ......
    

    }

    jContractList.jsp

    < font color ="000"> 查询条件 

    类型:

    ${comboContentStr}

    3、测试
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值