楼主: yulihua49

[讨论] 侃一下关于程序的“柔性”

[复制链接]
论坛徽章:
14
2009新春纪念徽章
日期:2009-01-04 14:52:28沸羊羊
日期:2015-03-04 14:51:52优秀写手
日期:2014-03-14 06:00:13马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:15蜘蛛蛋
日期:2012-06-27 21:08:142012新春纪念徽章
日期:2012-01-04 11:53:29ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
31#
 楼主| 发表于 2011-8-24 20:06 | 只看该作者
原帖由 nannan5000 于 2011-8-24 20:03 发表



正在看您和newkid之前的讨论。
我简单总结下

您是用DTO这类的机制实现了映射标准SQL,然后放到数据库去执行。 中间由中间件或MQ来传递格式化的数据。
前台处理的是struct。


newkid是相当于把struct每个属性都传到存储过程,存储过程来处理最后的业务逻辑(就是取票、锁定票之类的)。



yulihua49 我觉得您的系统完全可以跑在文件系统上,类似自己写个数据库。应该比Oracle能高效。貌似用Oracle挺贵的,用MySQL也能存数。

请指点,谢谢前辈!

您写的包装器很牛,望其项背,像您致敬!

文件系统没问题,连IBM的TPF都做了。
MYSQL还没做。DB2和SYBASE作了。

开始开发时是叫DTO后来改名DAU了,Data Access Unit。
开始没有绑定变量,后来newkid点拨,加上了bind,受益匪浅,不仅性能提高了,功能一下子活起来了,where子句可以自动生成了:WHERE colname1=:colname1 AND col2=:col2 ........。

如感兴趣参加QQ群SDBC:100807652,在群空间有文档和源码。

[ 本帖最后由 yulihua49 于 2011-8-24 20:17 编辑 ]

使用道具 举报

回复
招聘 : 多个岗位招聘
论坛徽章:
33
2010广州亚运会纪念徽章:跆拳道
日期:2010-11-22 15:42:39灰彻蛋
日期:2012-05-16 13:17:56参与WIN7挑战赛纪念
日期:2012-05-24 10:37:35茶鸡蛋
日期:2012-05-28 17:27:32灰彻蛋
日期:2012-06-13 18:48:14双黄蛋
日期:2012-06-14 14:32:02奥运会纪念徽章:帆船
日期:2012-07-10 09:43:29奥运会纪念徽章:足球
日期:2012-08-17 09:17:32奥运会纪念徽章:帆船
日期:2012-07-26 15:46:49奥运会纪念徽章:赛艇
日期:2012-08-20 16:23:58
32#
发表于 2011-8-24 20:17 | 只看该作者
其实架构的通用性也就是柔性
是和性能成反比的。

这个东西没有绝对的一个度在这,
有的公司就需要把业务逻辑都放到前台,后台就是个存数的。
有的公司就认为要充分利用数据库的特性,毕竟现在的数据库不是简单的存数的东西。

这里有一个小小的疑问,
一般成型的软件,都是和数据库配套的。一般不会轻易更换数据库。
举个不太恰当的例子,没听说金蝶的ERP从Oracle 换到DB2.

客户更多的应该是要实现他的需求,至于软件商使用什么技术,什么架构实现。他完全可以不关心。

在物尽其用这个方面,我还是支持newkid的观点的。

只是不知道你们的系统为什么要设计成通用数据库。

其它问题。请教淘宝DBA,为什么淘宝要把Oracle换到MySQL呢?

使用道具 举报

回复
论坛徽章:
14
2009新春纪念徽章
日期:2009-01-04 14:52:28沸羊羊
日期:2015-03-04 14:51:52优秀写手
日期:2014-03-14 06:00:13马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:15蜘蛛蛋
日期:2012-06-27 21:08:142012新春纪念徽章
日期:2012-01-04 11:53:29ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
33#
 楼主| 发表于 2011-8-24 20:22 | 只看该作者
原帖由 nannan5000 于 2011-8-24 20:17 发表
其实架构的通用性也就是柔性
是和性能成反比的。

这个东西没有绝对的一个度在这,
有的公司就需要把业务逻辑都放到前台,后台就是个存数的。
有的公司就认为要充分利用数据库的特性,毕竟现在的数据库不是简单的存数的东西。

这里有一个小小的疑问,
一般成型的软件,都是和数据库配套的。一般不会轻易更换数据库。
举个不太恰当的例子,没听说金蝶的ERP从Oracle 换到DB2.

客户更多的应该是要实现他的需求,至于软件商使用什么技术,什么架构实现。他完全可以不关心。

在物尽其用这个方面,我还是支持newkid的观点的。

只是不知道你们的系统为什么要设计成通用数据库。

其它问题。请教淘宝DBA,为什么淘宝要把Oracle换到MySQL呢?

做框架的应该尊重客户的需求。客户要求独立于数据库,我们就要支持。如ODBC,JDBC,hibernate都是如此。
如果你是个软件商,顾客买了你的软件,你还要强迫客户再买一个ORACLE?人家可能就不要你了。
同理你强迫你的客户买TUXEDO?所以中间件也必须可更换。所以我们也有自己的中间件。我们不搭售任何其它公司的产品。
这些也都是柔性编程的内容。

所以我们的软件分3层:
svc层,与中间件接口,app层:业务逻辑,DAO层:数据库接口。
哪层变化改哪层。

你看到了,我前边的样例,几乎看不到什么数据库,换到DB2也没问题的(只是分页查询的语句不同)。

包装的越深,越好用,效率越低。这是一般规律。DAU是个例外,它的运行效率远远高于一般的手写程序。
因为如果你想要自己写出那些高效率的代码,会累疯的。

[ 本帖最后由 yulihua49 于 2011-8-24 20:41 编辑 ]

使用道具 举报

回复
招聘 : 多个岗位招聘
论坛徽章:
33
2010广州亚运会纪念徽章:跆拳道
日期:2010-11-22 15:42:39灰彻蛋
日期:2012-05-16 13:17:56参与WIN7挑战赛纪念
日期:2012-05-24 10:37:35茶鸡蛋
日期:2012-05-28 17:27:32灰彻蛋
日期:2012-06-13 18:48:14双黄蛋
日期:2012-06-14 14:32:02奥运会纪念徽章:帆船
日期:2012-07-10 09:43:29奥运会纪念徽章:足球
日期:2012-08-17 09:17:32奥运会纪念徽章:帆船
日期:2012-07-26 15:46:49奥运会纪念徽章:赛艇
日期:2012-08-20 16:23:58
34#
发表于 2011-8-24 20:37 | 只看该作者
原帖由 yulihua49 于 2011-8-24 20:22 发表

做框架的应该尊重客户的需求。客户要求独立于数据库,我们就要支持。如ODBC,JDBC,hibernate都是如此。
如果你是个软件商,顾客买了你的软件,你还要强迫客户再买一个ORACLE?人家可能就不要你了。
同理你强迫你的客户买TUXEDO?所以中间件也必须可更换。所以我们也有自己的中间件。我们不搭售任何其它公司的产品。
这些也都是柔性编程的内容。




那我是不是可以这么理解,您说的柔性是指
项目涉及购买软件的灵活性,比如客户要买MQ,你就用MQ。否则就用你自己的中间件。
是这么理解么?

使用道具 举报

回复
论坛徽章:
14
2009新春纪念徽章
日期:2009-01-04 14:52:28沸羊羊
日期:2015-03-04 14:51:52优秀写手
日期:2014-03-14 06:00:13马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:15蜘蛛蛋
日期:2012-06-27 21:08:142012新春纪念徽章
日期:2012-01-04 11:53:29ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
35#
 楼主| 发表于 2011-8-24 20:38 | 只看该作者
原帖由 nannan5000 于 2011-8-24 20:37 发表




那我是不是可以这么理解,您说的柔性是指
项目涉及购买软件的灵活性,比如客户要买MQ,你就用MQ。否则就用你自己的中间件。
是这么理解么?

这是一个重要的方面。我们真的有一个MQ+TPF的版本。

[ 本帖最后由 yulihua49 于 2011-8-24 20:39 编辑 ]

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
36#
发表于 2011-8-24 21:56 | 只看该作者
原帖由 yulihua49 于 2011-8-24 14:54 发表

岂止是“重用性不高”,简直是出了你这样的高手中的高手,恐怕别人根本就无能为力。
给个题目:
由于安全要求,客户端不允熙直接连接数据库,要通过类似TUXEDO、东方通、SDBC或其他交易中间件接入。一般的交易是交易服务器完成,交易服务器接数据库。
系统有些字典性的表,大概几十个,如车站表,城市表,线路表,席别表,票种表,列车等级表等等,相对稳定的。客户端可能要把他们暂存在客户端数据库、数据文件或数据结构里。不定期的需要从主数据库里提取数据,可能取某一条记录,或符合某条件的一批记录,也可能全部。想提取的表可能增加也可能减少。这样你可能需要数十个服务来解决这些问题。能否用一个服务来解决字典数据提取问题?允许服务器使用存储过程或其他办法,最好是一个存储过程解决所有的表。


你这是夸我还是损我呢?一下子哭笑不得。
让你整个业务逻辑的例子,闹了半天还是整出个数据访问层的例子。这种需求就是取数据、传数据而已,和业务逻辑毫无关系,并不是PLSQL优势所在,但是要实现也未尝不可,DBMS_SQL搞定,我甚至用NATIVE DYNAMIC SQL也能搞定。

还有你这需求也很搞笑。照你说法是为了把静态的字典类数据传给前端做缓存。真要有这种需求,都是全表缓存的,你见过缓存一页的需求?简直是笑话。要么你还打算为分页查询服务?但是这又是个单表查询。

还要提醒你:未经排序的分页是没有意义的。

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
37#
发表于 2011-8-25 01:14 | 只看该作者



设置环境:用DBA对该用户授权:
GRANT CREATE ANY CONTEXT TO XXXXX;

这里把XXXXX换成你真正的用户名。

然后用XXXXX登录:

CREATE OR REPLACE CONTEXT APP_CTX USING get_data;
---- 上面创建的CONTEXT是为了传递绑定变量。

CREATE OR REPLACE PACKAGE get_data
AS
PROCEDURE read (
          p_output     OUT SYS_REFCURSOR
         ,p_tablename   IN VARCHAR2
         ,p_where       IN VARCHAR2
         ,p_page_size   IN NUMBER DEFAULT 0
         ,p_page_idx    IN NUMBER DEFAULT 0
         ,p_values      IN VARCHAR2
         );
END;
/



CREATE OR REPLACE PACKAGE BODY get_data
AS
PROCEDURE read (
          p_output     OUT SYS_REFCURSOR
         ,p_tablename   IN VARCHAR2
         ,p_where       IN VARCHAR2
         ,p_page_size   IN NUMBER DEFAULT 0
         ,p_page_idx    IN NUMBER DEFAULT 0
         ,p_values      IN VARCHAR2
         )
AS
  lv_sql           VARCHAR2(32000);
  lv_where         VARCHAR2(32000) := p_where;
  lv_current_col   VARCHAR2(30);
  lv_col_predicate VARCHAR2(100);
  lv_values        VARCHAR2(32000) := p_values;
  lv_val1          VARCHAR2(1000);
  lv_pos           NUMBER;
  lv_min           NUMBER;
  lv_max           NUMBER;
  lv_cnt           NUMBER :=0;
  lv_data_type     USER_TAB_COLUMNS.DATA_TYPE%TYPE;
  lv_date_format   VARCHAR2(20) := 'YYYYMMDDHH24MISS';
  lv_time_format   VARCHAR2(20) := 'YYYYMMDDHH24MISS';
BEGIN
  WHILE lv_values IS NOT NULL
  LOOP
      lv_pos := INSTR(lv_values,',');
      IF lv_pos>0 THEN
         lv_val1 := SUBSTR(lv_values,1,lv_pos-1);
         lv_values := SUBSTR(lv_values,lv_pos+1);
      ELSE
         lv_val1 := lv_values;
         lv_values := NULL;
      END IF;
      lv_pos := INSTR(lv_val1,':');
      lv_current_col := TRIM(BOTH '"' FROM SUBSTR(lv_val1,1,lv_pos-1));
      BEGIN
         SELECT data_type INTO lv_data_type FROM USER_TAB_COLUMNS WHERE TABLE_NAME = UPPER(p_tablename) AND COLUMN_NAME=UPPER(lv_current_col);
      EXCEPTION
         WHEN NO_DATA_FOUND THEN
              RAISE_APPLICATION_ERROR(-20001,'invalid column name in parameter:'||lv_current_col);
      END;

      lv_cnt := lv_cnt+1;
      DBMS_SESSION.SET_CONTEXT('APP_CTX','$P'||lv_cnt, TRIM(BOTH '"' FROM SUBSTR(lv_val1,lv_pos+1)));
      CASE
      WHEN lv_data_type = 'NUMBER' THEN
           lv_col_predicate := 'TO_NUMBER(SYS_CONTEXT(''APP_CTX'',''$P'||lv_cnt||'''))';
      WHEN lv_data_type ='DATE' THEN
           lv_col_predicate := 'TO_DATE(SYS_CONTEXT(''APP_CTX'',''$P'||lv_cnt||'''),'''||lv_date_format||''')';
      WHEN lv_data_type LIKE '%TIMESTAMP%' THEN
           lv_col_predicate := 'TO_TIMESTAMP(SYS_CONTEXT(''APP_CTX'',''$P'||lv_cnt||'''),'''||lv_time_format||''')';
      ELSE
           lv_col_predicate := 'SYS_CONTEXT(''APP_CTX'',''$P'||lv_cnt||''')';
      END CASE;
      lv_where := REGEXP_REPLACE(lv_where,':'||lv_current_col,lv_col_predicate,1,1,'i');

  END LOOP;
  
  FOR lv_col IN (SELECT * FROM USER_TAB_COLUMNS WHERE TABLE_NAME = UPPER(p_tablename) ORDER BY COLUMN_ID)
  LOOP
      IF lv_col.COLUMN_ID=1 THEN
         lv_sql := 'SELECT ''{''';
      ELSE
         lv_sql := lv_sql||'||'',''';
      END IF;

      CASE
      WHEN lv_col.DATA_TYPE ='DATE' THEN
           lv_sql := lv_sql||   '||''"'||lv_col.column_name||'":"''||TO_CHAR('||lv_col.column_name||','''||lv_date_format||''')||''"''';
      WHEN lv_col.DATA_TYPE LIKE '%TIMESTAMP%' THEN
           lv_sql := lv_sql||   '||''"'||lv_col.column_name||'":"''||TO_CHAR('||lv_col.column_name||','''||lv_time_format||''')||''"''';
      ELSE
           lv_sql := lv_sql||   '||''"'||lv_col.column_name||'":"''||'||lv_col.column_name||'||''"''';
      END CASE;

  END LOOP;
  lv_sql := lv_sql||'||''}'' AS json FROM '||p_tablename||' '||lv_where;
  
  IF p_page_size>0 AND p_page_idx>0 THEN
     lv_min := (p_page_idx-1)*p_page_size+1;
     lv_max := p_page_idx*p_page_size;
     lv_sql :='SELECT json FROM (SELECT json,ROWNUM rn FROM ('||lv_sql||') v WHERE ROWNUM<=:MAX_ROW) WHERE rn>= :MIN_ROW';
     OPEN p_output FOR lv_sql USING lv_max,lv_min;
  ELSE
     OPEN p_output FOR lv_sql;
  END IF;
  
  DBMS_OUTPUT.PUT_LINE(lv_sql);
  RETURN;
END read;

END get_data;
/

这样已经是全部代码,包含了楼主的最底层的DAU_XXXX 那些东西的功能!

客户端怎么调用呢?比楼主简单多了,就CALL一次存储过程,访问游标即可。

我甚至模拟了楼主的测试数据:

CREATE TABLE trn_mmnt (trn_no VARCHAR2(20), stn_no NUMBER, stn_name VARCHAR2(20), trn_lvr VARCHAR2(10), arrive_time VARCHAR2(10), departure_time VARCHAR2(10), days NUMBER, run_minuts NUMBER, stop_minuts NUMBER);

insert into trn_mmnt values ('G7154', 1, '上海虹桥',  '高速', ''     , '12:05', 0, 0,   0   );
insert into trn_mmnt values ('G7154', 2, '昆山南',    '高速', '12:23', '12:24', 0, 18,  1   );
insert into trn_mmnt values ('G7154', 3, '无锡',      '高速', '12:46', '12:48', 0, 41,  2   );
insert into trn_mmnt values ('G7154', 4, '常州',      '高速', '13:01', '13:02', 0, 56,  1   );
insert into trn_mmnt values ('G7154', 5, '丹阳',      '高速', '13:17', '13:18', 0, 72,  1   );
insert into trn_mmnt values ('G7154', 6, '丹徒',      '高速', '13:28', '13:29', 0, 83,  1   );
insert into trn_mmnt values ('G7154', 7, '镇江',      '高速', '13:37', '13:38', 0, 92,  1   );
insert into trn_mmnt values ('G7154', 8, '南京',      '高速', '13:59', ''     , 0, 114, -1  );

到SQL PLUS下,声明一个游标:

VAR VRES REFCURSOR;

EXEC get_data.read(:vres,'trn_mmnt','where trn_no=:trn_no order by stn_no',3,1,'"trn_no":"G7154"');

--- 看输出:
PRINT VRES;

JSON
------------------------------------------------------------------------------------------------------------------------------------------------------
{"TRN_NO":"G7154","STN_NO":"1","STN_NAME":"上海虹桥","TRN_LVR":"高速","ARRIVE_TIME":"","DEPARTURE_TIME":"12:05","DAYS":"0","RUN_MINUTS":"0","STOP_MINUTS":"0"}
{"TRN_NO":"G7154","STN_NO":"2","STN_NAME":"昆山南","TRN_LVR":"高速","ARRIVE_TIME":"12:23","DEPARTURE_TIME":"12:24","DAYS":"0","RUN_MINUTS":"18","STOP_MINUTS":"1"}
{"TRN_NO":"G7154","STN_NO":"3","STN_NAME":"无锡","TRN_LVR":"高速","ARRIVE_TIME":"12:46","DEPARTURE_TIME":"12:48","DAYS":"0","RUN_MINUTS":"41","STOP_MINUTS":"2"}




使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
38#
发表于 2011-8-25 01:16 | 只看该作者
看了楼主的例子,发现他还是有排序的,只是写在WHERE参数里面而已,有点令人困惑。

使用道具 举报

回复
论坛徽章:
38
授权会员
日期:2005-10-30 17:05:332012新春纪念徽章
日期:2012-02-13 15:12:09现任管理团队成员
日期:2011-11-07 09:46:59ITPUB十周年纪念徽章
日期:2011-11-01 16:19:41ITPUB9周年纪念徽章
日期:2010-10-08 09:31:21版主3段
日期:2012-05-15 15:24:112009新春纪念徽章
日期:2009-01-04 14:52:282010新春纪念徽章
日期:2010-03-01 11:06:202009日食纪念
日期:2009-07-22 09:30:00祖国60周年纪念徽章
日期:2009-10-09 08:28:00
39#
发表于 2011-8-25 01:16 | 只看该作者
原帖由 yulihua49 于 2011-8-24 14:51 发表

柔性的优势显而易见。
你除去某些列(这是应客户要求加上的功能),将来表改了。
如果删除了你除去的列,操作不会出错。如果你加上一些列,程序不修改,新加的列会自动包含在结果中。因此点名除去列要比点名包含列柔性更好。


你除去某些列(这是应客户要求加上的功能),
应客户要求加上功能,就去掉某些列?这种需求和设计挺希奇的,通常只听说增加列。

后台数据库里面删掉几个字段,前端居然不需要修改,这只能说明一个问题,你的前台根本就没有使用这几个字段,冗余。这和柔性有什么关系?

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
40#
发表于 2011-8-25 01:24 | 只看该作者
原帖由 yulihua49 于 2011-8-24 14:51 发表

柔性的优势显而易见。
你除去某些列(这是应客户要求加上的功能),将来表改了。
如果删除了你除去的列,操作不会出错。如果你加上一些列,程序不修改,新加的列会自动包含在结果中。因此点名除去列要比点名包含列柔性更好。


“将来表改了”假如是新增了列,你这个做法就会自动SELECT新列;假如减少列,则自动去除。
由此说明你这个应用根本就是透明的传输而已,它不是数据的消费者。新增的列要体现到业务中的,减少的列也要把原来的使用这个列的代码去掉。
再次重复我前面说过的话:这种透明的包装、传输只对你自己有用,PLSQL根本用不着。

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表