NPS自定义数据源的定制开发

在栏目管理中一旦输入自定义数据源表,系统将自动生成一个以自定义数据源表名+_prop命名的表,我们称为prop表,用于自定义数据源状态管理。其表结构如下:

CREATE TABLE 自定义数据源表名_prop (ID VARCHAR2(50) NOT NULL,
     TITLE VARCHAR2(1000) NOT NULL,
     SITEID VARCHAR2(10) NOT NULL,
     TOPIC VARCHAR2(10) NOT NULL,
     STATE NUMBER,
     CREATEDATE DATE DEFAULT SYSDATE NOT NULL,
     PUBLISHDATE DATE,
     CONSTRAINT PK_自定义数据源表名_prop PRIMARY KEY (ID,TOPIC)
);
COMMENT ON COLUMN 自定义数据源表名_prop.TITLE IS '显示用标题';
COMMENT ON COLUMN 自定义数据源表名_prop.SITEID IS '站点ID';
COMMENT ON COLUMN 自定义数据源表名_prop.TOPIC IS '栏目ID';
COMMENT ON COLUMN 自定义数据源表名_prop.STATE IS '状态';
COMMENT ON COLUMN 自定义数据源表名_prop.CREATEDATE IS '创建日期';
COMMENT ON COLUMN 自定义数据源表名_prop.PUBLISHDATE IS '发布日期';

See also

top

Class CustomArticle

所有自定义数据源类必须从CustomArticle派生。CustomArticle提供了默认情况下的自定义数据源的实现,有以下几个特点:
1.除id、title、createdate、publishdate字段外,其他都以TagRS格式存储。而TagRS类似一个以大写数据库字段名为索引的Hashtable;
2.不提供附件的操作。所有附件标签操作取值都是为空;
3.对系列NpsEvent提供了默认支持,这些事件仅对当前栏目发起的事件响应。
    1)InsertEvent事件默认响应:将数据插入Topic指定的prop表。如果Topic指定默认状态要求发布的,则发布之;
    2)UpdateEvent事件默认响应:更新prop表中title的值。如果当前文章状态为已发布或待发布的,则重新发布;
    3)DeleteEvent事件默认响应:如果文章已经发布,则删除所有静态页面、删除SOLR索引、删除prop表记录;
    4)Ready2PublishEvent事件默认响应:发布该文章,并自动生成PublishEvent公告;
    5)PublishEvent事件默认响应:送SOLR索引。
4.不提供前端的管理界面。如果需要在NPS中管理自定义数据源,需要进行二次开发。

构造函数
public CustomArticle(NpsContext inCtxt,Topic top,ResultSet rs) throws Exception
根据数据库结果集构造CustomArticle。注意,系统发布过程中自动加载的结果集,仅包含prop表和自定义数据源主表字段。

Product样例代码:
public Product(NpsContext inCtxt,Topic top,ResultSet rs) throws Exception
{
     super(inCtxt,rs.getString("id"),rs.getString("title"),top);

     //加载主要信息
     LoadMainInfo(rs,0);

     //加载本地信息
     LoadLocalInfos();

     //加载图片
     LoadAttaches();

     //加载通知用户
     LoadNotifyInfo();
}
IPublishable系列方法重载
public boolean HasFiled(String fieldName)
判断是否以fieldName命名的字段,如果有,返回true,否则返回false。

public Object GetField(String fieldName) throws NpsException
得到以fieldName命名的字段值。返回特定的Object对象。CLOB类型返回Reader对象。

Product样例代码:
public boolean HasFiled(String fieldName)
{
     if(fieldName==null || fieldName.length()==0) return false;
    
     String key = fieldName.trim();
     if(key.length()==0) return false;
    
     key = key.toUpperCase();
    
     if(key.equalsIgnoreCase("name")) return true;
     if(key.equalsIgnoreCase("code")) return true;//产品代码
     if(key.equalsIgnoreCase("category")) return true;
     if(key.equalsIgnoreCase("origin")) return true;
     if(key.equalsIgnoreCase("producer")) return true;
     if(key.equalsIgnoreCase("exporter")) return true;
     if(key.equalsIgnoreCase("brand")) return true;
     if(key.equalsIgnoreCase("material")) return true;
     if(key.equalsIgnoreCase("product_size")) return true;
     if(key.equalsIgnoreCase("product_weight")) return true;
     if(key.equalsIgnoreCase("carton")) return true;
     if(key.equalsIgnoreCase("carton_weight")) return true;
     if(key.equalsIgnoreCase("purchase_price")) return true;//进价
     if(key.equalsIgnoreCase("price")) return true;//进价
     if(key.equalsIgnoreCase("fob")) return true;
     if(key.equalsIgnoreCase("package_quantity")) return true;//包装数量
     if(key.equalsIgnoreCase("lead_time")) return true; //交货期
     if(key.equalsIgnoreCase("moq")) return true;//最小采购数
     if(key.equalsIgnoreCase("MinimumMoney")) return true;//最小下单金额
     if(key.equalsIgnoreCase("product_spec")) return true;
     if(key.equalsIgnoreCase("package_spec")) return true;
    
    
     if(fields==null) return false;
     return fields.HasField(key);
}

public Object GetField(String fieldName) throws NpsException
{
     if(fieldName==null || fieldName.length()==0) return null;
    
     String key = fieldName.trim();
     if(key.length()==0) return null;
    
     key = key.toUpperCase();
    
     if(key.equalsIgnoreCase("name")) return name;
     if(key.equalsIgnoreCase("code")) return code;//产品代码
     if(key.equalsIgnoreCase("category")) return category;
     if(key.equalsIgnoreCase("origin")) return origin;
     if(key.equalsIgnoreCase("producer")) return producer;
     if(key.equalsIgnoreCase("exporter")) return exporter;
     if(key.equalsIgnoreCase("brand")) return brand;
     if(key.equalsIgnoreCase("material")) return material;
     if(key.equalsIgnoreCase("product_size")) return product_size;
     if(key.equalsIgnoreCase("product_weight")) return product_weight;
     if(key.equalsIgnoreCase("carton")) return carton;
     if(key.equalsIgnoreCase("carton_weight")) return carton_weight;
     if(key.equalsIgnoreCase("purchase_price")) return purchase_price;//进价
     if(key.equalsIgnoreCase("price")) return purchase_price;//进价
     if(key.equalsIgnoreCase("fob")) return fob;
     if(key.equalsIgnoreCase("package_quantity")) return package_quantity;//包装数量
     if(key.equalsIgnoreCase("lead_time")) return lead_time; //交货期
     if(key.equalsIgnoreCase("moq")) return moq;//最小采购数
     if(key.equalsIgnoreCase("MinimumMoney")) return GetMinimumMoney();//最小下单金额
     if(key.equalsIgnoreCase("product_spec")) return product_spec;
     if(key.equalsIgnoreCase("package_spec")) return package_spec;


     if(fields==null) return null;
     return fields.GetField(key);
}
发布事件通知
通过EventIssue的Fire系列方法发布事件通知,注意Fire方法中的key值,应取值为自定义数据源表名(大写)。
Product样例代码:
//发布准备好发布消息,让各栏目计划发布
public void Publish() throws NpsException
{
     //Fire Event
     EventIssue.GetIssue().FireReady2PublishEvent(this,"FT_PRODUCT");
}
NpsEvent事件处理
如果默认的事件处理无法满足要求,就需要对NpsEvent处理函数进行重载。
public void Insert(Object observer, InsertEvent event)
对InsertEvent事件的响应函数。

public void Update(Object observer, UpdateEvent event)
对UpdateEvent事件的响应函数。

public void Delete(Object observer, DeleteEvent event)
对DeleteEvent事件的响应函数。

public void Ready(Object observer, Ready2PublishEvent event)
对Ready2PublishEvent事件的响应函数。

public void Publish(Object observer, PublishEvent event)
对PublishEvent事件的响应函数。

Product样例代码:
//本单位栏目仅关心自己的产品
public void Insert(Object observer, InsertEvent event)
{
     if(observer instanceof Topic)
     {
         Topic t = (Topic)observer;
         if(!unit_id.equals(t.GetSite().GetUnit().GetId())) return;
         super.Insert(t,event);
     }
}
top

Class Attach

Attach类是所有附件类的基类。Article类负责Attach集合的管理。

IPublishable接口实现
public String GetURL()
返回发布后的Attach的URL路径。

public File GetOutputFile()
返回临时文件存放位置。

Product样例代码:
public String GetURL()
{
     return PRODUCT_ATTACH_URL
     + Utils.FormateDate( art.GetCreateDate() , "yyyy/MM/dd")
     + "/"
     + id
     + (suffix==null?"":suffix);
}
    
public File GetOutputFile()
{
     String temp_filepath = Utils.FormateDate(art.GetCreateDate(),"yyyy/MM/dd") +"/";
    
     temp_filepath = temp_filepath.replaceAll("//","/");
     if(temp_filepath.startsWith("/"))
     {
         temp_filepath = temp_filepath.substring(1);
     }
    
     File temp_file = new File( PRODUCT_ATTACH_PATH,temp_filepath);
    
     temp_file.mkdirs();
    
     return new File(temp_file, id + (suffix==null?"":suffix));
}
Cloneable接口实现
public Object clone() throws CloneNotSupportedException
提供对象clone实现。默认实现如下:
public Object clone() throws CloneNotSupportedException
{
     return super.clone();
}
top

custom.xml配置

Java类开发完成后,需要配置custom.xml实现自动加载。

存放位置
custom.xml存放在与nps.conf相同的目录下,即WEB-INF目录下。
配置说明
<?xml version="1.0" encoding="UTF-8"?>
<root>
    #每一类自定义数据单独放在一个CustomArticle节点下,root节点下CustomArticle接口可以多个。
     <CustomArticle>
         #每个CustomArticle节点必须有且只有一个table和class节点,否则加载时将被忽略。
         #table是指要监控的自定义数据源表名,应大写。
         #class是指要加载的二次开发的自定义数据源名,建议使用类全名,类必须放在common/lib、WEB-INF/classes、WEB-INF/lib下。
         <table>FT_PRODUCT</table>
         <class>nps.extra.trade.Product</class>

         #property节点不是必须的,仅在需要自定义配置时才需要使用。property是全局共享的。
         #property下级节点名称为property变量名,值为变量的取值,注意,值是trim后结果。
         <property>
             <PRODUCT_ATTACH_PATH>c:\\web\\products\\</PRODUCT_ATTACH_PATH>
             <PRODUCT_ATTACH_URL>/products/</PRODUCT_ATTACH_URL>
        </property>
     </CustomArticle>

         #event节点不是必须的,仅在需要自定义事件处理时才需要配置。对于CustomArticle派生类重载的NpsEvent处理方法,系统将在启动时自动加载,无需配置。
         #event下只能有insert、update、delete、ready、publish四种节点,分别与InsertEvent、UpdateEvent、DeleteEvent、Ready2PublishEvent、PublishEvent事件对应。
         #key值为自定义数据源中发布事件通知的KEY值。
         #下面的Product样例是用于在产品publish后自动给客户发送电子邮件通知服务。
     <event>
         <publish key="FT_PRODUCT">nps.extra.trade.ProductManager</publish>
     </event>
</root>