1. 通用编码规范

    1. 通常不允许写try .. catch ..finally代码,因为框架中会自动将异常抛出到前台界面及日志中,方便问题的跟踪,如果在比较特殊的情况下要自定义捕捉异常并进行处理,异常不能采用e.printStackTrace()类似写法,一定要采用common.error(e)或common.error(msg, e)抛出,如:catch (Exception e) { common.error(e) }。
    2. 不允许使用System.out.println(msg)方式打印调试日志,必须采用统一的log.debug、log.info、log.warn、log.error方式打印日志,这样日志可以通过log4j的配置来定义是否显示日志,另外如果日志中的数据很大,如打印集合类对象,最好先判断是否打印日志再确定是否执行日志打印代码,如if (log.isDebug()) log.deug(dataset),因为如果不做isDebug判断,就算日志未显示,但log.debug(dataset)也将执行,而dataset.toString()在数据量大的情况将影响执行效率。
    3. 中断操作抛出提示到前台,采用common.error(msg)方式,如:if (x == null) common.error("数据不存在")
    4. 不允许自定义数据库连接,避免出现连接池泄漏,连接的提交回滚等由框架管理,通常只需要在定义new XxxDAO()或new XxxDAO("sdstat")方式来获取默认或指定名的连接,数据库连接默认为非自动提交方式,如果要手工提交或回滚,可以通过pd.getDBConn()或pd.getDBConn("sdstat")来获取连接然后执行commit或rollback操作,如果在特殊场景下,需要自己申请并自己管理连接,需要自定义PageData对象,并定义rollback和close连接,如:
      PageData pd = new PageData();
      try {
      	...
      } catch (Exception e) {
      	pd.rollbackConnections();
      	common.error(e);
      } finally {
      	pd.cleanupConnections();
      }
      
    5. Timer定时任务Task中,由原来的extends Task改为extends AppTask,这样将不需要自己申请并控制连接,简化代码并提高统一性,如:
      public class FlowTask extends AppTask {
      	public IData execute(IData params) throws Exception {
      		...
      	}
      }
      
    6. 导出时,分页模型尽量用new Pagination(true),这样导出不会占用太多资源,每次只会占用一页数据资源,如queyrList(pd, data, new Pagination(true))
    7. Session对象自定义的取值和赋值,统一采用pd.getContext().setAttribute(key ,value)pd.getContext().getAttribute(key, value)
    8. 工广类需继承AppFactory,DAO需继承AppEntity,Bean需继承AppBen,Servlet需继承AppServlet,Page需继承AppPage,组件类需要继承AppComponent,AppTemeletComponent,AppFormComponent,或着继承这些类的子类,编写方式如下:
      public class XXXFactory extends AppFactory
      public class XXXBean extends AppBean
      public class XXXDAO extends AppEntity
      public class XXXTask extends AppTask
      
    9. 在域下新建upload目录下需要五个子目录,否则上传附件图片、导入导出等无法正确执行,目录如下:
      upload/attach:存放上传附件
      upload/image:存放上传图片
      upload/export:存放定制导出文件
      upload/import:存放导入失败文件
      upload/temp:存放临时文件
    10. Session的使用,session一般用于存储权限、员工信息等,原则上不允许业务数据存放在session对象中,否则会导致服务器端内存过大,而且会造成程序的不稳定,如果要对session操作,必须通过pg.getContext()方式操作。
  2. DAO编码规范

    1. 所有DAO类必须继承AppEntity,如果需要用到指定连接,必须加上构造函数,这样保证DAO的逻辑与数据库连接的分离,如:
      public XxxDAO(PageData pd, String connName) throws Exception {
      	super(pd, connName);
      }
      
    2. 简单的表操作,包括单表增、删、改、查看,以及批量的单表操作,都不要自己写SQL,而是通过insert、update、save、delete、queryByPk等方式完成。
    3. SQLParser中,addSQL为自动匹配:VAR_NAME,若存在VAR_NAME的值,则拼装该SQL,每个addSQL只允许一个VAR_NAME,如:parser.addSQL(" and vip.VIP_ID = :VIP_ID"),对于like方式的sql,需要写成:parser.addSQL(" and vip.USECUST_NAME like '%' || :USECUST_NAME || '%'");
    4. 动态SQL和固定SQL的使用场景,如果根据传入的条件需要SQL动态变化采用动态SQL,如果SQL的变量固定,采用固定SQL,如:queryList("select * from TF_M_STAFF_ID wehre STAFF_ID = ?", new Object() { staff_id})
    5. 批量数据提交尽量采用批量操作,如insert(table, dataset)等,若自定义SQL的批量操作,通过executeBatch方式实现,如:
      String sql = "insert into TI_O_SMS (SMS_NOTICE_ID, EPARCHY_CODE) values (f_uip_getseqid('SEQ_SMSSEND_ID'), ?)";
      Parameter[] params = new Parameter[values.length];
      for (int i=0; i<params.length; i++) {
      	params[i] = new Parameter();
      	params[i].add(values[i]);
      }
      executeBatch(sql.toString(), params);
      
    6. DAO里编写SQL时要注意不要用SQL里的关键字做别名,如:
      String sql = "insert into TI_O_SMS (SMS_NOTICE_ID, EPARCHY_CODE) values (f_uip_getseqid('SEQ_SMSSEND_ID'), ?)";
      Parameter[] params = new Parameter[values.length];
      for (int i=0; i<params.length; i++) {
      	params[i] = new Parameter();
      	params[i].add(values[i]);
      }
      executeBatch(sql.toString(), params);
      

      这样的代码不会被正确执行
    7. 所有子系统需要规定DAO里SQL代码的写法,包括大小写、空格等,这样不仅提高代码的统一还可以大大提高SQL的可重用性。
    8. SQLParser的SQL需要添加where 1 = 1,并且将每个条件写在一行内,正确代码如下:
      SQLParser parser = new SQLParser(param);
      parser.addSQL("select vip.* from TF_F_CUST_VIP vip where 1 = 1");
      parser.addSQL(" and vip.IN_DATE >= to_date(:START_DATE, 'yyyy-mm-dd')");
      
    9. 所有子系统需要规定DAO里SQL代码的写法,包括大小写、空格等,这样不仅提高代码的统一还可以大大提高SQL的可重用性。
    10. 如果表UTIL_SCHEDULE没有主键或者有多个主键,但希望指定相应的列对数据更新,可以在update、save方法后面加上参数new String[] { “SCHE_ID”, “SCHE_STATE” },程序将会将根据绑定的列名和值对数据更新,默认没有这个参数的话,是根据表结构主键进行更新,如dao.save("UTIL_SCHEDULE", data, new String[] { “SCHE_ID”, “SCHE_STATE” });按SCHE_ID和SCHE_STATE更新data中的数据。
    11. save和update的区别:update会将data中的所有数据更新,如果表字段原有的信息在data中没有指定,则这些信息会被清空,而save则会先去查出原记录的所有信息,再将需要更新的数据覆盖后更新。通常,如果只是部分更新表字段的数据,则必须用save方法,除非data中的数据已经包含所有需要修改的信息,则用update方法,这样效率会高些。
  3. Bean编码规范

    1. 所有Bean类必须继承AppBean,否则无法保证统一和兼容性。
    2. Bean类方法中用来处理业务逻辑,如果需要操作DAO方法,必须构造DAO对象,若要指定数据库连接,构造DAO时指定即可,这样保证Bean逻辑与数据库连接的解耦,提高DAO逻辑的通用性,若调用中心库,必须使用AppFactory.CENTER_CONNECTION_NAME,如:
      XxxDAO dao = new XxxDAO(pd);
      XxxDAO dao = new XxxDAO(pd, "sdstat");
      XxxDAO dao = new XxxDAO(pd,  AppFactory.CENTER_CONNECTION_NAME);
      
    3. 主要考虑同一个页面如果打开多次,或者有多个人同时访问,而在你更新之前已有人删除或修改过信息的状态,这样就需要传递目前获取的关键数据列,如主键,状态来识别信息是否能够修改,假如删除了,或者状态已被变更过则不能删除。为了避免这种情况代码应写成:
      If (bean.deleteSchedule(pd, pd.getParamter(“SCHE_ID”), pd.getParameter(“SCHE_STATUS”)})) common.error(“删除失败,信息在此前已被操作过”)
      
    4. 对于分库的情况,如果是对中心库的表进行增、删、改、按主键查的情况,要使用中心库的连接进行操作。
  4. View编码规范

    1. 所有的子系统要实现各自的基类,如QuickstartPage(标准验证登录),QuickstartSafePage(不验证登录),各子系统的页面类继承这两个基类。
    2. 事件响应方法中最好不要写太复杂的逻辑,只做些逻辑的调用,页面输入的校验以及数据值的映射,复杂的业务逻辑由后台逻辑来完成,保证后来逻辑的完整性。
    3. 构造PageData对象时,统一采用PageData pd = getPageData(),这样保证一个完整逻辑时只会用到一个PageData上下文对象。
    4. 不允许写全局成员方法,如:public List list = new ArrayList(),这样会导致数据在下次打开页面时还存留了上次执行的数据,而且这种情况在windows上不会出现,所以开发时无法发现,如果一定要用,需要在页面的pageDetach()方法中清调去全局成员对象的值,如:
      public void pageDetach(PageEvent event) {
      super.pageDetach(event);
      list = null;
      }
      
    5. 尽量用public abstact void setInfo(IData info)这种抽象方式来实现数据源的映射。
    6. 响应事件的方法参数必须为IRequestCycle,如:
      public void deleteFiles(IRequestCycle cycle) throws Exception
      
    7. redirectTo和redirectToMsg等页面跳转和提示方式的使用场景,必须为Submit方式提交才能有效果,如通过链接或者ajax方式时该操作将无效。
    8. 在获取数据时,如果发现数据取不到或者发生ClassCastException异常,同时将取到的所有数据打印到后台日志中,发现错误数据的值为[Ljava.lang.String时,需要检查生成的html中是否有重复同名的对象。
    9. Page 'XXXPageName' not found in application namespace,此种错误是.application文件中没有指定page文件的路径,或者是更改.application文件后没有重启WEB服务器。