1. 模块化与解耦规范

1.1. 写在规范之前

无论做多么小的功能组件,编码时自省,要思考以下问题

  • Basic
    • 数组是否做了边界判断。
    • 入参是否进行了空指针防护。
  • 性能
    • 大循环中是否会多次访问数据库。
    • 是否使用了同步锁,如果使用同步锁,粒度要尽可能细。
  • 安全
    • 是否不登录就可以访问,返回值是否包含敏感信息。
    • 是否根据前端传入的用户Id返回指定的信息,而不是根据当前用户。
  • 集群
    • 是否要支持集群,如果使用Timer是否要控制只在主节点运行。
    • 需不需要缓存同步,缓存是否存储了太多数据。
  • 依赖(升级和兼容性)
    • 是否引入第三方依赖,第三方依赖是否支持JDK6,对于WAS和WLS是否有可能有影响。
  • 日志:
    • 是否输出太多Info级别的日志。
    • 是否输出了必要的信息便于排查(利用好debug和trace)
  • 资源释放
    • 连接池是否在finally中close。
    • 是否有打开未关闭的Stream。
  • 内存(数据量):
    • 是否做了分页,内存里预期上限会有多少条数据。
  • 线程安全
    • 是否使用了线程安全的集合
    • 反之,方法内部变量不要使用线程安全的集合

1.2. 编码规范

一致性高于一切

1.2.1. 命名

编码和命名沿用Java编码规范,保持语义一致。

禁止使用个人姓名或昵称用于任何地方作为名称,产品是企业行为,不要带个性化的特征。

分类 命名 备注
Package com.seeyon.apps.{moduleName}.api 全部小写
Interface com.seeyon.apps.{moduleName}.api.XXXApi 如com.seeyon.apps.news.api.NewsApi
Impl com.seeyon.apps.{moduleName}.api.XXXApiImpl 如com.seeyon.apps.news.api.NewsApiImpl,实现代码放在具体的模块工程
Bean Name xXXApi 如newsApi
Spring xml File Name spring-{moduleName}-api.xml 如spring-news-api.xml
Param com.seeyon.apps.{moduleName}.api.XXXParam 方法参数超出3个需引入Param对象作为参数
PO com.seeyon.apps.{moduleName}.po 统一,方便维护

所有的接口方法必须抛出异常,异常类型为BusinessException

void run() throws BusinessException;

示例:

import com.seeyon.apps.news.api.NewsApi;
import com.seeyon.apps.news.api.NewsParam;
...
NewsApi api;
long id;
api.get(id);
api.get(new NewsParam(newsType,pageNum,pageSize));

bean定义放在具体模块的工程,如spring-news-api.xml

<bean name="newsApi" class="com.seeyon.apps.news.api.NewsApiImpl"/>

方法命名

命名采用"动作+属性" 的方法。并且,动作以小写字母开始,属性以大写字母开始。常用的动作有:is、get、set、create、 update、delete。 遵从业界惯例,for可缩写为4,to可缩写为2

分类 命名 备注
新建 createXXX 不用insert,公告发布可使用issue,协同发送使用send,但须申请并增补到术语表中
修改 updateXXX 不用modify、save
删除 deleteXXX 不用remove
查询-单一对象 get 无数据统一返回null,不允许抛出异常
查询-对象列表 find 不用search、query,无数据不允许返回null,返回Collections.emptyList()
查询-全部对象 findAll 无数据时处理同上
查询-对象计数 getXXXCount -

新建、修改和删除不允许使用boolean或int作为返回值,原则上应该是void的

long id;
String subject;
NewsType type;
// 按Id取
News aNews = api.get(id);
// 按某一特定的规则取,如果不会产生歧义,就不必加ByName、BySubject
News aNews = api.get(subject);
// 获取指定条件的列表
List<News> newsList = api.find(type);
// 获取所有
List<News> all = api.findAll();

1.2.2. 日志

日志使用我们封装的CtpLogFactory,变量名统一使用LOG

import org.apache.commons.logging.Log;
import com.seeyon.ctp.common.log.CtpLogFactory;

public class NewsApiImpl {
    private final Log LOG = CtpLogFactory.getLog(NewsApiImpl.class);
}

分页:迁移代码继续使用Pagination,CTP的新实现继续沿用Flipinfo,不再引入新的分页对象。

当前用户:区分用户的所有接口实现均不允许内部获取CurrentUser,必须显性传入memberId。

1.2.3. 参数设计规范

  1. 参数名应能从字面表明参数的作用

  2. 参数对象不允许使用基础数据类型,必须使用其封装类作为参数类型。如参数需要传Integer类型的,不允许使用int。

  3. 接口中写明的参数在使用时都必须有用,不允许出现其中某个参数为特定值时,可以忽略另一个参数的情况。如有特殊的需求,建议拆分接口为多个。如findBulletinTypes(int spaceType, long accountId)方法,在spaceType为-1时,不管accountId为任何值,都会返回所有的公告板块列表。这样的接口就会产生使用上的歧义,建议增加一个接口findAllBulletinTypes()取代这种情况。

  4. 8种基础数据类型的参数,使用封装类型

    // 正确
    void methodOk(Long l,Integer i,Boolean b){
    }
    // 错误
    void methodBad(long l,int i,boolean b){
    }
    

接口方法参数和返回值不允许传递第三方组件的实体,如JSONObject、JAXP对象,以避免无谓的第三方组件替换和升级代价。

1.2.4. 模块管理

模块使用唯一的int值进行标识。

  • 内部模块必须在com.seeyon.ctp.common.constants.ApplicationCategoryEnum枚举中定义。

    合并com.seeyon.ctp.common.ModuleType,统一使用com.seeyon.ctp.common.constants.ApplicationCategoryEnum

  • 外部扩展应用可以不在枚举中添加。

  • 0-10000为内部模块预留编号,外部扩展应用不允许使用。

  • 方法定义和调用方式如下,注意,参数必须为 int ,参数名称必须为 category

    // 正确定义
    List<AppLog> getAllAppLogs(int category);
    
    // 错误定义
    List<AppLog> getAllAppLogs(ApplicationCategoryEnum appEnum);
    
    // 正确调用
    getAllAppLogs(ApplicationCategoryEnum.global.getKey());
    getAllAppLogs(10021);
    
    // 错误调用
    getAllAppLogs(0);
    

目前的模块定义如下

标识 名称 备注
global 0 全局
collaboration 1 协同应用
form 2 表单
doc 3 知识管理
edoc 4 公文
plan 5 计划
meeting 6 会议
bulletin 7 公告
news 8 新闻
bbs 9 讨论
inquiry 10 调查
calendar 11 日程事件
mail 12 邮件
organization 13 组织模型
project 14 项目
relateMember 15 关联人员
exchange 16 交换
hr 17 人力资源
blog 18 博客
edocSend 19 发文
edocRec 20 收文
edocSign 21 签报
exSend 22 待发送公文
exSign 23 待签收公文
edocRegister 24 待登记公文
communication 25 在线交流
office 26 综合办公
agent 27 代理设置
modifyPassword 28 密码修改
meetingroom 29 会议室
taskManage 30 任务管理
guestbook 31 留言板
info 32 信息报送
infoStat 33 信息报送统计
edocRecDistribute 34 收文分发
notice 35 公示板
attendance 36 签到
mobileAppMgrForHTML5 37 移动应用接入-html5应用包
sapPlugin 38 sap插件
ThirdPartyIntegration 39 第三方整合

img

1.2.5. Maven

价值

  1. 控制内部模块间依赖。

  2. 管理第三方类库,避免版本冲突。

  3. 自动化构建。

引入Maven管理依赖,文件放置遵从Maven的标准: Eclipse工程文件(.project、.classpath)请勿提交到svn上。

目录结构

http://10.3.4.218:6666/
   └── svn
      └── v5
         ├── ctp                                                               Ctp基础框架,包括原core和T1
         │   └── trunk
         │      ├── ctp-core
         │      │   └── pom.xml
         │      ├── ctp-common                                                 平台基础组件,原ctp_t1
         │      │   └── pom.xml
         │      └── pom.xml
         ├── ctp-organization                                                  组织模型,原ctp_t2
         │   └── trunk
         │      └── pom.xml
         ├── ctp-portal                                                        门户,原ctp_t3
         │   └── trunk
         │      └── pom.xml
         ├── ctp-workflow                                                      工作流,原ctp_t4
         │   └── trunk
         │      └── pom.xml
         ├── ctp-report                                                        报表
         │   └── trunk
         │      └── pom.xml
         ├── ctp-form                                                          表单,原ctp_t5
         │   └── trunk
         │      └── pom.xml
         ├── ctp-index                                                         全文检索引擎
         │   └── trunk
         │      └── pom.xml
         ├── apps-api                                                          解耦后的开放接口
         │   └── trunk
         │      └── pom.xml
         ├── apps-common                                                       应用基础组件
         │   └── trunk
         │      └── pom.xml
         ├── apps-collaboration                                                协同应用,原f1
         │   └── trunk
         │      └── pom.xml
         ├── apps-task                                                         任务
         │   └── trunk
         │      └── pom.xml
         ├── apps-calendar                                                     日程
         │   └── trunk
         │      └── pom.xml
         ├── apps-plan                                                         计划
         │   └── trunk
         │      └── pom.xml
         ├── apps-project                                                      项目
         │   └── trunk
         │      └── pom.xml
         ├── apps-f7
         │   └── trunk
         │      ├── apps-edoc                                                  公文
         │      │   └── pom.xml
         │      ├── apps-exchange                                              公文交换
         │      │   └── pom.xml                      
         │      └── pom.xml
         ├── apps-colcube                                                      协同立方
         │   └── trunk
         │      └── pom.xml
         ├── apps-performancereport                                            
         │   └── trunk
         │      └── pom.xml
         ├── apps-meeting                                                      会议
         │   └── trunk
         │      └── pom.xml
         ├── apps-meetingroom                                                  会议室
         │   └── trunk
         │      └── pom.xml
         ├── apps-meetingsummary 
         │   └── trunk
         │      └── pom.xml
         ├── apps-office
         │   └── trunk
         │      └── pom.xml
         ├── apps-pubresource
         │   └── trunk
         │      └── pom.xml
         ├── apps-index                                                       全文检索应用
         │   └── trunk
         │      └── pom.xml
         ├── apps-blog
         │   └── trunk
         │      └── pom.xml
         ├── apps-doc                                                         文档中心
         │   └── trunk
         │      └── pom.xml
         ├── apps-rss
         │   └── trunk
         │      └── pom.xml
         ├── apps-uc
         │   └── trunk
         │      └── pom.xml
         ├── apps-addressbook                                                 通讯录
         │   └── trunk
         │      └── pom.xml
         ├── apps-bbs                                                         BBS
         │   └── trunk
         │      └── pom.xml
         ├── apps-bulletin                                                    公告
         │   └── trunk
         │      └── pom.xml
         ├── apps-inquery                                                     调查
         │   └── trunk
         │      └── pom.xml
         ├── apps-webmail                
         │   └── trunk
         │      └── pom.xml
         └── apps-hr
            └── trunk
               └── pom.xml

根据发布要求,支持两种目录结构的Project:

  1. 需要单独发布的模块使用自己的trunk,可单独打Tag和Branch,如apps-collaboration。

  2. 多个小模块可使用同一trunk,合并版本发布,采用多模块目录结构,如上例中的ctp-core和ctp-common。

标准Project目录结构

apps-xxx/                                    http://10.3.4.218:6666/svn/v5/apps-xxx/trunk
   ├── src
   │   ├── main
   │   │   ├── java
   │   │   │   └── com
   │   │   │      └── seeyon
   │   │   ├── resources
   │   │   └── webapp
   │   │      ├── WEB-INF
   │   │      │   └── web.xml
   │   │      └── index.jsp
   │   └── test
   │      ├── java
   │      │   └── com
   │      │      └── seeyon
   │      └── resources
   └── pom.xml

分模块目录结构

apps-xxx/                                    http://10.3.4.218:6666/svn/v5/apps-xxx/trunk
   ├── apps-news
   │   ├── src
   │   │   ├── main
   │   │   │   ├── java
   │   │   │   │   └── com
   │   │   │   │      └── seeyon
   │   │   │   ├── resources
   │   │   │   └── webapp
   │   │   │      ├── WEB-INF
   │   │   │      │   └── web.xml
   │   │   │      └── index.jsp
   │   │   └── test
   │   │      ├── java
   │   │      │   └── com
   │   │      │      └── seeyon
   │   │      └── resources
   │   └── pom.xml
   ├── apps-bbs
   │   ├── src
   │   │   ├── main
   │   │   │   ├── java
   │   │   │   │   └── com
   │   │   │   │      └── seeyon
   │   │   │   ├── resources
   │   │   │   └── webapp
   │   │   │      ├── WEB-INF
   │   │   │      │   └── web.xml
   │   │   │      └── index.jsp
   │   │   └── test
   │   │      ├── java
   │   │      │   └── com
   │   │      │      └── seeyon
   │   │      └── resources
   │   └── pom.xml
   └── pom.xml

解耦后工程代码结构如下

API调用

应用调用其它模块的API时,请使用依赖注入获取实例。

因为应用解耦的控制,不确保API有实现,所以必须在调用前判断API是否为null,如

  private NewsApi newsApi;

  public void foo(){
      if(newsApi!=null){
          newsApi.doSth();
      }
  }

在我们已实现的代码中,大家经常使用hasPlugin来替代判null,但这有一个前提条件,你必须清楚这个API是属于哪个插件的,而且也不排除你写错了插件Id的可能性。

另外,API层的价值在于,二次开发可以用自己的实现完整的替换我们的标准实现,如果它的插件Id不是你所判断的那个呢!

版本管理

遵从语义化版本规范,jar的命名规则为

seeyon-{分类}-{模块名称}-{主版本}.{次版本}.{增量版本}-{里程碑版本}.jar


分类取值为ctp、apps、api
模块名称如core、collaboration

如 seeyon-ctp-core-1.1.12-alpha-1.jar
  • 除非发生重大架构变更,今后很长一段时间,我们的主版本号均使用1,如 seeyon-ctp-core-1.2.1
  • 增加了新特性次改变版本号。
  • 进行了重大Bug修复时改变增量版本号。
  • 里程碑版本如 alpha-1、beta-2
  • 版本号记录在meta中,release时去除jar的版本号 示例如下

seeyon-ctp-common

seeyon-ctp-organization

seeyon-ctp-portal

seeyon-ctp-workflow

seeyon-ctp-report

seeyon-apps-collaboration

seeyon-apps-news

seeyon-apps-meeting

POM

值域 取值 备注
Group Id com.seeyon.{category} category取值范围为ctp、apps、api,如com.seeyon.ctp、com.seeyon.apps、com.seeyon.api
Artifact Id {category}-{moduleName} category同上,如ctp-core、apps-collaboration、apps-news
Version -
Packaging jar -

产品部署包版本

  • ftp目录:productPack/v5/6.0/
  • 文件名 : SVN版本号+产品内容

1.2.6. 文档规范

面向开发、测试和维护人员。

详细的文档帮助开发人员快速学习,降低解释成本。

详细的文档有助于单元测试建立用例,保证代码质量。

详细的文档有助于后续的维护人员管理。

使用Markdown作为设计和开发手册文档工具。 使用javadoc编写API文档,文档可以使用Markdown语法,。

  • 文档在Interface中编写,Impl不需重复。
  • 需写清楚场景
/**
   * <pre>
   * 得到我能访问的组
   * 正常情况:
   * 1、普通用户包括(前提是这个单位下的组):
   * 1.1 我建的私有组
   * 1.2 我是成员或关联人员系统组
   * 1.3 公开范围有我的系统组(单位、集团、项目)
   * <del>1.4 我是部门管理员的部门系统组</del>
   *
   * 2、单位管理员:
   * 2.1 这个单位所有的单位系统组(不包括部门组)
   * 2.2 集团公开范围有这个单位的系统组
   *
   * 3、集团、审计、系统管理员管理员
   * 3.1 所有的集团系统组
   * 3.2 这个单位的系统组
   * <del>2. 公开范围有我的系统组</del>
   *
   * 4.其它:
   * 4.1 看到集团组的前提是单位在集团树下
   * </pre>
   *
   *
   * @param memberId 人员id
   * @param accountId 单位id,每次都返回集团组
   * @return 组实体列表
   * @throws BusinessException
   */
    List<V3xOrgTeam> getTeamsByMember(Long memberId, Long accountId) throws BusinessException;
  • PO的文档统一写在setter方法上,getter不用赘述。
  • 善用@link
  /**
   * 按Id取岗位。 如果id为空或-1,则返回未分配岗位(id为{@link com.seeyon..organization.domain.OrgEntity#DEFAULT_NULL_ID 空})。
   * 
   * @param id
   *            岗位Id
   * @return 岗位实体
   * @throws BusinessException
   */
  V3xOrgPost getPostById(Long id) throws BusinessException;
  • 参数和返回值要写清楚各种取值的含义
  /**
   * 获取岗位下的人员,支持标准岗
   * <pre>
   * /--- PostId --|-- accountId --|--------------- 返回值 ------------/
   * |   标准岗    |   null/集团ID |   全集团所有单位引用自建岗下的人员  |
   * |   标准岗    |   单位ID      |   指定单位引用自建岗下的人员        |
   * |   单位自建岗|   此参数被忽略|   指定单位引用自建岗下的人员        |
   * </pre>
   * 
   * @param postId
   * @param accountId
   * @return
   * @throws BusinessException
   */
  public List<V3xOrgMember> getMembersByPost(Long postId, Long accountId) throws BusinessException;
  • 后续追加的接口和方法要写清楚支持的版本
@since 5.0Sp2

@since 5.1Sp1 m201411
  • 支持并强烈建议使用Markdown语法书写javadoc

      /**
       * 获取岗位下的人员,支持集团基准岗,限制单位可见范围
       * 
       * - 首先
       * - 其次
       * 
       * ```java
       *     // 示例代码
       *     OrgManager orgManager;
       *     orgManager.getMembersByPost4Access();
       *
    
    • | PostId | accountId | 返回值 |
    • |-------------------------|---------------|-------------------------------------|
    • | 标准岗 | null/集团ID | 全集团所有单位引用自建岗下的人员 |
    • | 标准岗 | 单位ID | 指定单位引用自建岗下的人员 |
    • | 单位自建岗 | 此参数被忽略| 指定单位引用自建岗下的人员 |
    • @param postId 岗位id
    • @param accountId 当前登录者的当前登录单位id
    • @return
    • @throws BusinessException */ List getMembersByPost4Access(Long postId, Long accountId) throws BusinessException; ```
  • 使用中文标点符号。

1.3. 插件启停用监听

解耦以后,为支持插件的灵活控制,允许在运行期改变插件的启用状态。

这样就带来了一个问题,以公告为例,如果在公告插件未启用的状态下新建单位,公告板块等信息无法进行初始化,此时就需要我们在公告插件启用时进行补偿。

为此,平台提供了com.seeyon.ctp.common.plugin.PluginChangeEvent插件状态变更事件,便于应用监听进行补偿。

应用可以实现一个监听器,例如:

import com.seeyon.ctp.common.plugin.PluginChangeEvent;
import com.seeyon.ctp.util.annotation.ListenEvent;
public class BbsPluginChangeListener{
    @ListenEvent(event = PluginAddEvent.class)
    public void onPluginAdd(PluginAddEvent evt) {
        Set<String> plugins = evt.getPlugins();
        if (Strings.isNotEmpty(plugins) && plugins.contains("bbs")) {
            log.info("bbs插件补偿");
            try {
                // 遍历各单位,确定是否未初始化板块信息;如未初始化,则进行补偿。
                List<V3xOrgAccount> allAccounts = orgManager.getAllAccounts();
                if (Strings.isNotEmpty(allAccounts)) {
                    for (V3xOrgAccount account : allAccounts) {
                        if (!account.isGroup()) {
                            bbsBoardManager.initBbsBoard(account.getId());
                        }
                    }
                }
            } catch (Exception e) {
                log.error("bbs插件补偿:", e);
            }
        }
    }
}

补偿列表

插件 补偿点
news 初始化新闻板块
bulletin 初始化公告板块
inquiry 初始化调查板块
bbs 初始化讨论板块
doc 添加单位系统文档库
office 初始化综合办公
hr 初始化HR数据
wechat 微协同补偿
colcube 新增协同立方指标
show 初始化秀
project 初始化关联项目
collaboration 初始化系统预置模板分类
edoc 初始化公文元素、节点权限、常用语
edoc 初始化文单等
infoopen 初始化信息报送
meeting 初始化会议资源、会议用品
portal 初始化单位空间

1.4. MVC开发规范

  1. bean的id一定要使用接口的名称,首字母小写,简化注入,便于调用。

  2. 不要使用Spring的init-method,请继承com.seeyon.ctp.common.AbstractSystemInitializer,在initialize方法中进行bean的初始化操作。

    <!-- 这样是不允许的!!! -->
    <bean id="iframeSection" class="com.seeyon.ctp.portal.section.bridge.IframeSection" init-method="init"/>
    
  3. 明确MVC各层职责,不能错误使用。

    例如Manager不能替代Dao的职责。

    HTTPRequest、HTTPResponse和HTTPSession只能出现在Controller,不允许传递到Manager层。

  4. Controller层不允许编写业务逻辑,业务逻辑由Manager层处理。

    Controller层的一个方法只能调用Manager层中的一个方法,目的是为了确保统一事务。

    错误:

    public class CollaborationController {
        private CollaborationManager collaborationManager;
        private AttachmentManager attachementManager;
        public ModelAndView newCol(){
            collaborationManager.save(...);
            attachementManager.save(...);
        }
    }
    
    public class CollaborationManagerImpl implements CollaborationManager{
        public void save(){
            ...
        }
    }
    

    正确:

    public class CollaborationController {
        private CollaborationManager collaborationManager;
        public ModelAndView newCol(){
            collaborationManager.save(...);
        }
    }
    public class CollaborationManagerImpl implements CollaborationManager{
        private AttachmentManager attachementManager;
        public void save(){
            ...
            attachementManager.save(...);
        }
    }
    
  5. Controller职责不宜过多,原则上一个Controller只封装一个完整业务逻辑(CRUD)。

  6. Manager层中分简单复杂(或大小)方法,之间可以互相调用,目的是完成完整的业务逻辑。(Manager本身就一层,并非像图中的三层,图中体现的是跨模块的Manager调用。)

  7. Manager和Dao层遵循接口开发要求,例如:Manager、ManagerImpl、Dao,DaoImpl。

  8. 所有的异常需要抛到Manager层,由Manager层统一Catch后包装为BusinessException抛出。

    Manager的方法不允许抛出BusinessException之外的异常。

    建议Manager的所有方法都抛出BusinessException,但不作硬性要求(初期不抛,后续版本抛出异常会影响到调用代码);

  9. Dao不能省略,必须定义。

  10. Dao层支持Hibernate和JDBC两种方式。

    原则上只允许使用Hibernate模式访问数据库。调用JDBC需评审并备案。

  11. 只有Dao层能够书写HQL和SQL语句,Controller和Manager层不允许出现SQL。

  12. 各层之间数据传递规范,PO与对应表字段一一对应,不允许增加额外的属性,不允许有业务逻辑;

    PO需继承BasePO,BasePO中已实现toXml、toJSON,出于性能考虑可以覆盖实现。

  13. C层向V层只能返回VO对象,VO对象为类Map的结构。对于简单情况可以用PO代替VO。

    命名规范:XXX模块对应的MVC、DAO对应各层的命名规范为 XXXController、XXXManager、XXXDao、XXXPO、spring-XXX-controller.xml、spring-XXX-manager.xml、xxx.hbm.xml

  14. 基于接口编码,Manager和Dao必须定义接口,一个接口一个实现类。

  15. 应用不允许自己调用Log4j,相应的日志由框架统一使用AOP记录。

  16. 按模块和功能划分package,原则上一个package不能超过10对类(接口+实现)。

1.4.1. 工具规范

  1. 插件化

框架插件机制提供了全面的插件扩展开发支持,包括插件启动、插件自定义配置文件、i18n、spring和hibernate PO加载等

1.4.2. 插件规范

  1. 插件相关的配置文件存放于cfgHome/plugin目录中,文件夹名称需与插件id保持一致。其中包括插件基础配置、插件自定义配置文件、插件i18n国际化配置、

    spring配置文件

  2. 插件代码包必须在“com.seeyon.apps.插件id”,比如com.seeyon.apps.samples

  3. 插件的PO对象和配置文件必须在“com.seeyon.apps.插件id.po”下,可以带子包用于配置自定义HQL的hbm文件

1.4.3. 插件基础配置

插件基础配置文件位于“cfgHome/plugin/插件id”目录下,文件名必须为pluginCfg.xml,例子如下:

<?xml version="1.0" encoding="UTF-8"?>
<plugin>
    <id>samples</id>                                   
    <name>例子模块</name>                               
    <category>10000</category>
</plugin>
TAG 备注
id 插件id,
name 插件名称
category 插件类别,产品插件分类从10000至19999,客开插件从20000开始

1.4.4. 插件启动初始化

系统启动时可以进行插件的启动和系统停止时的销毁操作,需继承自com.seeyon.ctp.common.AbstractSystemInitializer,并在spring中注册即可,例子代码如下

import com.seeyon.ctp.common.AbstractSystemInitializer;

public class SamplesInitializer extends AbstractSystemInitializer {
    public void destroy() {
        System.out.println("销毁Samples模块");
    }

    public void initialize() {
        System.out.println("初始化Samples模块");
    }
}

Spring注册例子如下(插件相关spring配置文件命名规则为spring-插件id-plugin.xml):

<bean name="samples_systemInitializer" class="com.seeyon.apps.samples.SamplesInitializer">
  <property name="sortOrder">
    <value>7</value>
  </property>
</bean>
<bean name="samples_systemInitializer2" class="com.seeyon.apps.samples.SamplesInitializer2">
  <property name="sortOrder">
    <value>2</value>
  </property>
</bean>

其中sortOrder为插件初始化顺序从小到大执行,如果没有配置该属性,则优先执行,在没有配置的多个初始化类之间顺序不定

1.4.5. 插件自定义配置文件

插件自定义配置文件位于“cfgHome/plugin/插件id”目录下,文件名必须为pluginProperties.xml,例子如下:

<?xml version="1.0" encoding="utf-8"?>
<ctpConfig>
    <samples>
        <test name="test配置">插件配置测试</test>
    </samples>
</ctpConfig>

该例中可通过AppContext.getSystemProperty("samples.test.name")取得“test配置”,AppContext.getSystemProperty("samples.test")取得“插件配置测试”

注意:属性key必须以插件id开始

1.4.6. 插件国际化配置文件

插件国际化配置文件位于“cfgHome/plugin/插件id/i18n”目录下,按照JDK国际化文件的配置规则命名,可采用多组文件。使用方式请参考i18n国际化组件部分说明。

注意:属性key必须以插件id开始

默认插件国际化资源配置只能后台使用(ResourceUtil接口,国际化页面function - ctp:i18n),前端javascript无法使用,如果要开放给前端,可以在插件的i18n

文件夹根下创建名为“export_to_js.xml”导出为javascript的$.i18n函数可使用的国际化资源,具体请参考国际化一节

如何转换V5的国际化文件?

1.下载可读V5国际化语言包(下载请鼠标右键-链接地址另存为): A8-V5-6.0SP1国际化语言包 A8-V5-6.1国际化语言包

2.下载【可读V5国际化语言包】后,可以根据意思转换为其他语言包,注意转换后也要保持与【可读V5国际化语言包】文件路径一致。

3.新语言包用JDK的native2ascii.exe工具再做一次Unicode编码转换。

命令示例:native2ascii.exe common_zh_CN.properties

1.4.7. 插件spring配置

插件spring配置文件位于“cfgHome/plugin/插件id/spring”目录下,可有多个spring配置文件,按照框架规范命名包括:

  1. spring-插件id-controller.xml controller配置,url需要形如“/插件id/xxx.do”
  2. spring-插件id-manager.xml manager配置,bean id需要形如“插件id_mgr_xxx”
  3. spring-插件id-dao.xml dao配置,bean id需要形如“插件id_dao_xxx”

1.4.8. 插件hibernatePO加载

插件的PO对象和配置文件必须在“com.seeyon.apps.插件id.po”下,可以带子包用于配置自定义HQL的hbm文件

1.5. 一致性要求

  1. 开发工具 建议使用Eclipse idea绝对禁止使用破解版

    如果觉得VSCode顺手,也可以用它

  2. 设计工具

    框图可使用Visio或直接使用Powerpoint,不做特别限制,但必须提交底稿。

    UML相关(用例、时序图、类图)推荐使用EA。

  3. 数据建模工具

    使用PowerDesigner

  4. JDK

    使用JDK 1.8,编译级别设为1.6。

    8.0以后允许使用1.8语法

  5. 第三方组件引入的原则

    注意开源组件的版权协议,避免侵权。

    已有同类组件的,如果不是在性能和特性上有绝对的优势,不引入。

    不引入三年内频繁上报高危安全问题的组件,请查询https://www.cvedetails.com

    不引入多年未维护社区不活跃的第三方组件。

  6. XML解析器

    只允许使用dom4j

    对于将XML解析为Bean,建议使用Commons Digester。

    XML配置解析建议使用Commons Configuration。

  7. 服务器端JSON解析

    统一使用框架提供的com.seeyon.ctp.util.json.JSONUtil,不要自己去封装或调用fastjson或Jackson,不允许使用org.json或net.sf.json,以便框架统一升级替换。

  8. 当前用户 不允许应用自行创建User对象设置到当前用户,请统一使用UserUtil的build方法创建,setCurrentUser方法设置。

  9. 模板引擎

    请勿自行引入freemarker或velocity等,统一使用smarty。

  10. 字符串处理 请使用com.seeyon.ctp.util.Strings的一系列工具方法:isBlank、isEmpty、toHTML、escapeJavascript等。

  11. 日期处理 统一使用com.seeyon.ctp.util.Datetimes,因为框架的实现带了多时区的处理,绝对禁止使用DateFormat。

    // Bad
    DateFormat df = new SimpleDateFormat("yyyy-mm-dd");
    String sDate = df.format(date);
    Date date = df.parse("2018-10-10");
    // Good
    String sDate =Datetimes.formatDatetime(date);
    Date date = Datetimes.parseDate("2018-10-10");
    
  12. 无头浏览器 统一使用phantomjs。

  13. HttpClient 统一使用平台提供的HttpClientUtil。

  14. Content Type Controller输出js、json或css时,必须使用准确的ContentType,切勿图省事使用text/html。

results matching ""

    No results matching ""