zoukankan      html  css  js  c++  java
  • robotframework笔记24

    侦听器接口

    机器人框架有一个侦听器接口,可以用于接收 对测试执行通知。 示例用法包括 外部测试监控,测试失败时发送邮件消息, 与其他系统进行通信。 侦听器API版本3也使得 它可以修改测试在测试执行和结果。

    侦听器类或模块与某些特殊的方法,和他们 可以用Python和Java实现。 侦听器监控 整个测试执行必须纳入使用从命令行。 除此之外, 测试库可以注册侦听器 接收 通知,图书馆是活跃的。

    监听使用

    监听被使用从命令行 ——侦听器 选项,侦听器是给它的名称作为参数。 的 侦听器的名称叫从类或模块实现 监听器接口,同样 测试库的名字 从类 实现它们。 指定监听器必须是相同的 模块搜索 路径 在测试库搜索时都是进口的。 其他 选择是给听众一个绝对或相对路径文件 同样与测试库 。 可以把多个侦听器 通过多次使用这个选项使用:

    robot --listener MyListener tests.robot
    robot --listener com.company.package.Listener tests.robot
    robot --listener path/to/MyListener.py tests.robot
    robot --listener module.Listener --listener AnotherListener tests.robot
    

    还可以给侦听器类从命令参数 线。 参数指定侦听器后名称使用冒号(或路径) ( )作为分隔符。 如果一个侦听器作为一个绝对Windows路径, 冒号后驱动器并不被视为分隔符。 从 2.8.7机器人框架,可以使用分号( )作为 替代参数分隔符。 这是有用的侦听器参数 包含冒号,但是需要周围的整个价值 引用在类unix操作系统:

    robot --listener listener.py:arg1:arg2 tests.robot
    robot --listener "listener.py;arg:with:colons" tests.robot
    robot --listener C:PathListener.py;D:data;E:extra tests.robot
    

    侦听器接口版本

    有两个版本支持侦听器接口。 侦听器版本2 因为机器人框架2.1,支持版本3 机器人3.0和新框架。 一个监听器必须有属性 ROBOT_LISTENER_API_VERSION 值2或3,作为字符串或作为 整数,这取决于它所使用的API版本。 也有一个年长的 侦听器版本1,但是它不支持了由机器人框架3.0。

    侦听器版本2和3之间的主要区别是前者 得到执行,但不能直接影响它的信息。 后者 接口获取数据和结果对象机器人框架本身使用,因此 能改变执行和变化的结果。 看到 侦听器的例子 更多的 信息的听众能做什么。

    另一个版本2和3之间的区别是,前者支持 Python和Java,但后者只支持Python。

    侦听器接口方法

    机器人框架测试执行时创建侦听器类的实例 直接启动和使用监听器实现模块。 在测试期间 执行不同的侦听器方法时调用测试套件、测试用例 和关键词的开始和结束。 额外的方法被称为当图书馆或 资源或变量文件导入,当输出文件准备好了, 最后整个测试执行结束时。 不需要一个侦听器 实现任何官方接口,它只需要它的方法 实际的需求。

    侦听器版本2和3有基本相同的方法,但是参数 他们接受是不同的。 这些方法及其参数解释道 在接下来的部分。 所有的方法都有一个强调以他们的名义 也 camelCase 的选择。 例如,start_suite 方法可以 也有使用的名字 startSuite 

    侦听器版本2

    侦听器API版本2中的方法在下表中列出。 所有方法与测试执行进展具有相同的签名 方法(名称、属性) ,在那里 属性 是一个词典,它包含 事件的细节。 侦听器方法可以自由做任何他们想做的事 他们收到的信息,但他们不能直接改变 它。 如果这是必要的, 侦听器版本3 可以使用。

    在侦听器API方法2
    方法参数文档
    start_suite 名称、属性

    当一个测试套件的开始。

    内容属性字典:

    • id :套件id。 s1 的顶层套房, s1-s1 第一个孩子套件, s1-s2 对于第二个 孩子,等等。 在射频2.8.5新。
    • longname :套件名称包括父套件。
    • 医生 :套件文档。
    • 元数据 免费测试套件的元数据 作为一个字典/地图。
    • 源 :文件/目录的绝对路径 被创建的。 新在射频2.7。
    • 套房 :直接儿童套房此套件的名称 作为一个列表。
    • 测试 :测试此套件的名称列表。 不包括测试可能的儿童套房。
    • totaltests :在此套件测试的总数。 及其所有sub-suites作为一个整数。
    • 开始时间 :套件执行开始时间。
    end_suite 名称、属性

    当一个测试套件。

    内容属性字典:

    • id :一样 start_suite 
    • longname :一样 start_suite 
    • 医生 :一样 start_suite 
    • 元数据 :一样 start_suite 
    • 源 :一样 start_suite 
    • 开始时间 :一样 start_suite 
    • endtime :套件执行结束时间。
    • elapsedtime :总执行时间以毫秒为单位 一个整数
    • 状态 :套件作为字符串 通过 或 失败 
    • 统计数据 :套件统计(传递的数量 和失败的测试套件)作为一个字符串。
    • 消息 :错误消息如果套件安装或拆卸 没有,否则空。
    start_test 名称、属性

    当一个测试用例开始。

    内容属性字典:

    • id :测试id等格式 s1-s2-t2 ,在那里 一开始是父组件id和最后一部分 显示测试套件的指数。 在射频2.8.5新。
    • longname 父套件包括:测试名称。
    • 医生 :测试文档。
    • 标签 :测试标签作为一个字符串列表。
    • 至关重要的 是的 或 没有 根据测试被认为是 至关重要的。
    • 模板 :用于测试模板的名称。 一个空字符串如果测试没有模板化。
    • 开始时间 测试执行:执行开始时间。
    end_test 名称、属性

    当测试用例结束。

    内容属性字典:

    • id :一样 start_test 
    • longname :一样 start_test 
    • 医生 :一样 start_test 
    • 标签 :一样 start_test 
    • 至关重要的 :一样 start_test 
    • 模板 :一样 start_test 
    • 开始时间 :一样 start_test 
    • endtime 测试执行:执行结束时间。
    • elapsedtime :总执行时间以毫秒为单位 一个整数
    • 状态 :测试作为字符串 通过 或 失败 
    • 消息 :状态信息。 通常一个错误 消息或一个空字符串。
    start_keyword 名称、属性

    当一个字开始。

    的名字 是完整的包含关键字的名字吗 可能的库或资源名称作为前缀。 例如, MyLibrary。 例子的关键字 

    内容属性字典:

    • 类型 :字符串 关键字 普通关键字, 设置 或 拆卸 的顶级关键词作为安装/拆卸, 为 for循环, 为项目 对个人for循环 迭代。注意: 关键字类型报告了 3.0射频。 看到问题 # 2248 获取详细信息。
    • kwname :没有库或关键字的名字 资源前缀。 新在射频2.9。
    • 库名 :图书馆或资源的名称 关键词属于,或一个空字符串 关键字在一个测试用例文件。 新在射频2.9。
    • 医生 :关键字的文档。
    • arg游戏 :关键字参数作为一个字符串列表。
    • 分配 :一个变量名,关键字的列表 返回值分配给。 新在射频2.9。
    • 标签 关键字标签 作为一个字符串列表。 新在射频3.0。
    • 开始时间 :关键字执行开始时间。
    end_keyword 名称、属性

    一个关键字结束的时候叫。

    的名字 是完整的包含关键字的名字吗 可能的库或资源名称作为前缀。 例如, MyLibrary。 例子的关键字 

    内容属性字典:

    • 类型 :一样 start_keyword 
    • kwname :一样 start_keyword 
    • 库名 :一样 start_keyword 
    • 医生 :一样 start_keyword 
    • arg游戏 :一样 start_keyword 
    • 分配 :一样 start_keyword 
    • 标签 :一样 start_keyword 
    • 开始时间 :一样 start_keyword 
    • endtime :关键字执行结束时间。
    • elapsedtime :总执行时间以毫秒为单位 一个整数
    • 状态 :关键字作为字符串 通过 或 失败 
    log_message 消息

    当执行一个字写一个日志消息。

    消息 是一个字典,以下内容:

    • 消息 :消息的内容。
    • 水平 日志级别 用于日志消息。
    • 时间戳 :消息创建时间格式 YYYY-MM-DD hh:mm:ss.mil 
    • html :字符串 是的 或 没有 表示消息是否 应该解释为HTML或不是。

    3.0从射频,调用这个方法并不是如果消息 低于当前水平吗 阈值水平 

    消息 消息

    框架本身写时调用的方法 syslog 消息。

    消息 字典的内容是一样的吗 log_message 方法。

    library_import 名称、属性

    时调用一个图书馆已导入。

    的名字 是导入的库的名称。 如果图书馆 使用进口吗 与名语法 的名字 是 指定的别名。

    内容属性字典:

    • arg游戏 :参数传递给库列表。
    • originalname 当使用:原库的名字 与名语法,否则一样 的名字 
    • 源 :绝对路径库源。 没有一个 与库与Java或者得到实现 源库失败的一些原因。
    • 进口国 :一个绝对路径文件导入 图书馆。 没有一个 当 内装式 当导入得好吗 使用 导入库 关键字。

    2.9新机器人框架。

    resource_import 名称、属性

    当一个资源文件导入。

    的名字 是导入的资源文件的名字没有 文件扩展名。

    内容属性字典:

    • 源 :导入的资源文件的绝对路径。
    • 进口国 :一个绝对路径文件导入 资源文件。 没有一个 当使用 进口资源 关键字。

    2.9新机器人框架。

    variables_import 名称、属性

    时调用一个变量文件导入。

    的名字 是进口变量文件的名称 文件扩展名。

    内容属性字典:

    • arg游戏 :参数传递到变量文件作为一个列表。
    • 源 :进口变量文件的绝对路径。
    • 进口国 :一个绝对路径文件导入 资源文件。 没有一个 当使用 进口 变量 关键字。

    2.9新机器人框架。

    output_file 路径

    当编写一个 输出文件 已经准备好了。

    路径 是一个绝对路径文件。

    log_file 路径

    当写作 日志文件 已经准备好了。

    路径 是一个绝对路径文件。

    report_file 路径

    当写作 报告文件 已经准备好了。

    路径 是一个绝对路径文件。

    xunit_file 路径

    当编写一个 xunit文件 已经准备好了。

    路径 是一个绝对路径文件。

    debug_file 路径

    当写作 调试文件 已经准备好了。

    路径 是一个绝对路径文件。

    关闭  

    整个测试执行结束时调用。

    与 图书馆的听众 外出时调用图书馆 的范围。

    可用的方法和他们的论点也正式Java所示 下面的接口规范。 的内容 java.util。 映射属性 是 如上表。 它应该记得一个侦听器 不 需要 实现任何显式接口或者所有这些方法。

    public interface RobotListenerInterface {
        public static final int ROBOT_LISTENER_API_VERSION = 2;
        void startSuite(String name, java.util.Map attributes);
        void endSuite(String name, java.util.Map attributes);
        void startTest(String name, java.util.Map attributes);
        void endTest(String name, java.util.Map attributes);
        void startKeyword(String name, java.util.Map attributes);
        void endKeyword(String name, java.util.Map attributes);
        void logMessage(java.util.Map message);
        void message(java.util.Map message);
        void outputFile(String path);
        void logFile(String path);
        void reportFile(String path);
        void debugFile(String path);
        void close();
    }
    

    侦听器版本3

    侦听器版本3相同的方法 侦听器版本2 但相关参数的方法测试执行是不同的。 这个API得到实际运行和结果模型对象所使用的机器人 框架本身,听众可以直接查询信息 他们需要和动态变化的模型对象。

    侦听器版本3是在机器人框架3.0中引入的。 至少 最初它没有版本2的所有方法。 的 主要原因是 合适的模型对象内部不可用 。 的 关闭 方法和方法相关的输出文件被称为完全 在两个版本一样。

    在侦听器API方法3
    方法参数文档
    start_suite 数据,结果

    当一个测试套件的开始。

    数据 和 结果 模型对象是代表 的 执行测试套件 和 它的 执行结果 ,分别。

    end_suite 数据,结果

    当一个测试套件。

    同样的参数作为 start_suite 

    start_test 数据,结果

    当一个测试用例开始。

    数据 和 结果 模型对象是代表 的 执行测试用例 和 它的 执行结果 ,分别。

    end_test 数据,结果

    当测试用例结束。

    同样的参数作为 start_test 

    start_keyword N /一个 在射频3.0中没有实现。
    end_keyword N /一个 在射频3.0中没有实现。
    log_message 消息

    当执行一个字写一个日志消息。 消息 是一个模型对象代表 记录 消息 

    调用这个方法并不是如果消息级别以下 当前的 阈值水平 

    消息 消息

    框架本身写时调用的方法 syslog 消息。

    消息 是相同的对象 log_message 

    library_import N /一个 在射频3.0中没有实现。
    resource_import N /一个 在射频3.0中没有实现。
    variables_import N /一个 在射频3.0中没有实现。
    output_file 路径

    当编写一个 输出文件 已经准备好了。

    路径 是一个绝对路径文件。

    log_file 路径

    当写作 日志文件 已经准备好了。

    路径 是一个绝对路径文件。

    report_file 路径

    当写作 报告文件 已经准备好了。

    路径 是一个绝对路径文件。

    xunit_file 路径

    当编写一个 xunit文件 已经准备好了。

    路径 是一个绝对路径文件。

    debug_file 路径

    当写作 调试文件 已经准备好了。

    路径 是一个绝对路径文件。

    关闭  

    整个测试执行结束时调用。

    与 图书馆的听众 外出时调用图书馆 的范围。

    4.3.4听众日志

    机器人提供了一个框架 程序化的日志记录api 听众可以 利用。 有一些局限性,然而,不同的听众 方法可以日志消息在下面的表格说明。

    侦听器方法如何记录
    方法解释
    start_keyword, end_keyword, log_message 消息记录到正常 日志文件 根据关键字执行。
    start_suite, end_suite, start_test,end_test 消息记录到 syslog 。 警告 所示的 执行错误 的部分 正常的日志文件。
    消息 syslog消息通常是记录。 如果 这个方法用于执行关键字时, 消息记录到日志文件正常。
    其他方法 只记录到syslog的消息。

    请注意

    为了避免递归,听众不发送消息记录 侦听器方法 log_message 和 消息 

    侦听器的例子

    本节包含的例子使用侦听器接口。 有 第一个例子,刚从机器人框架,然后接收信息 示例修改执行测试并创建的结果。

    获取信息

    第一个例子是作为Python模块实现和使用 侦听器 版本2 

    """Listener that stops execution if a test fails."""
    
    ROBOT_LISTENER_API_VERSION = 2
    
    def end_test(name, attrs):
        if attrs['status'] == 'FAIL':
            print 'Test "%s" failed: %s' % (name, attrs['message'])
            raw_input('Press enter to continue.')
    

    如果上面的例子将被保存,例如, PauseExecution.py 文件,可以使用它从命令行如下:

    robot --listener path/to/PauseExecution.py tests.robot
    

    同样的例子也可以使用更新的实现 侦听器版本3 和使用完全相同的方式从命令行。

    """Listener that stops execution if a test fails."""
    
    ROBOT_LISTENER_API_VERSION = 3
    
    def end_test(data, result):
        if not result.passed:
            print 'Test "%s" failed: %s' % (result.name, result.message)
            raw_input('Press enter to continue.')
    

    下一个示例,它仍然使用Python,稍微复杂一些。 它 写它到一个文本文件的所有信息在一个临时目录中 没有格式。 文件名可以从命令行,但是 也有一个默认值。 请注意,在实际使用中, 调试文件 功能可以通过命令行选项 ——debugfile 是 可能比这个例子更有用。

    import os.path
    import tempfile
    
    
    class PythonListener:
        ROBOT_LISTENER_API_VERSION = 2
    
        def __init__(self, filename='listen.txt'):
            outpath = os.path.join(tempfile.gettempdir(), filename)
            self.outfile = open(outpath, 'w')
    
        def start_suite(self, name, attrs):
            self.outfile.write("%s '%s'
    " % (name, attrs['doc']))
    
        def start_test(self, name, attrs):
            tags = ' '.join(attrs['tags'])
            self.outfile.write("- %s '%s' [ %s ] :: " % (name, attrs['doc'], tags))
    
        def end_test(self, name, attrs):
            if attrs['status'] == 'PASS':
                self.outfile.write('PASS
    ')
            else:
                self.outfile.write('FAIL: %s
    ' % attrs['message'])
    
         def end_suite(self, name, attrs):
             self.outfile.write('%s
    %s
    ' % (attrs['status'], attrs['message']))
    
         def close(self):
             self.outfile.close()
    

    下面的示例实现了与上一个相同的功能, 但使用Java,而不是Python。

    import java.io.*;
    import java.util.Map;
    import java.util.List;
    
    
    public class JavaListener {
        public static final int ROBOT_LISTENER_API_VERSION = 2;
        public static final String DEFAULT_FILENAME = "listen_java.txt";
        private BufferedWriter outfile = null;
    
        public JavaListener() throws IOException {
            this(DEFAULT_FILENAME);
        }
    
        public JavaListener(String filename) throws IOException {
            String tmpdir = System.getProperty("java.io.tmpdir");
            String sep = System.getProperty("file.separator");
            String outpath = tmpdir + sep + filename;
            outfile = new BufferedWriter(new FileWriter(outpath));
        }
    
        public void startSuite(String name, Map attrs) throws IOException {
            outfile.write(name + " '" + attrs.get("doc") + "'
    ");
        }
    
        public void startTest(String name, Map attrs) throws IOException {
            outfile.write("- " + name + " '" + attrs.get("doc") + "' [ ");
            List tags = (List)attrs.get("tags");
            for (int i=0; i < tags.size(); i++) {
               outfile.write(tags.get(i) + " ");
            }
            outfile.write(" ] :: ");
        }
    
        public void endTest(String name, Map attrs) throws IOException {
            String status = attrs.get("status").toString();
            if (status.equals("PASS")) {
                outfile.write("PASS
    ");
            }
            else {
                outfile.write("FAIL: " + attrs.get("message") + "
    ");
            }
        }
    
        public void endSuite(String name, Map attrs) throws IOException {
            outfile.write(attrs.get("status") + "
    " + attrs.get("message") + "
    ");
        }
    
        public void close() throws IOException {
            outfile.close();
        }
    }
    

    修改执行和结果

    这些例子说明如何修改执行测试和套房 以及执行结果。 所有这些例子都需要使用 的 侦听器版本3 

    修改测试套件和执行

    改变是什么需要修改模型对象包含执行 的执行 测试套件 或 测试用例 作为第一个参数传递给对象 start_suite 和 start_test 方法。 下面的示例所示 添加一个新的测试,每个测试套件和一个新的关键字来执行每个测试。

    ROBOT_LISTENER_API_VERSION = 3
    
    def start_suite(suite, result):
        suite.tests.create(name='New test')
    
    def start_test(test, result):
        test.keywords.create(name='Log', args=['Keyword added by listener!'])
    

    试图修改执行 end_suite 或 end_test 方法不工作, 仅仅因为这套房或测试已经执行。 试图修改 名称、文档或其他类似的当前套件或元数据 测试 start_suite 或 start_test 方法不奏效,因为 相应的结果对象已经创建。 只有改变 实际上孩子测试或关键词有影响。

    这个API非常相似 跑前修饰符 可以使用API 修改套件和测试在整个测试执行开始之前。 主要的 使用侦听器API的好处是,可以做修改 根据执行结果或动态。 例如,这使得 基于模型的测试的有趣的可能性。

    尽管侦听器接口不是机器人框架之上的 内部 访问接口 同样是跑前修改器API, 听众自己仍然可以使用游客接口。 例如, 的 SelectEveryXthTest 客人使用 跑前修饰符 例子可以 使用这样的:

    from SelectEveryXthTest import SelectEveryXthTest
    
    ROBOT_LISTENER_API_VERSION = 3
    
    def start_suite(suite, result):
        selector = SelectEveryXthTest(x=2)
        suite.visit(selector)
    
    修改的结果

    测试执行结果可以被修改 测试套件 和 测试用例 结果对象 作为第二个参数传递 start_suite 和 start_test 方法, 分别通过修改 消息 对象传递 到 log_message 方法。 这是证明了下面的听众 这是作为一个类实现。

    class ResultModifier(object):
        ROBOT_LISTENER_API_VERSION = 3
    
        def __init__(self, max_seconds=10):
            self.max_milliseconds = float(max_seconds) * 1000
    
       def start_suite(self, data, suite):
           suite.doc = 'Documentation set by listener.'
           # Information about tests only available via data at this point.
           smoke_tests = [test for test in data.tests if 'smoke' in test.tags]
           suite.metadata['Smoke tests'] = len(smoke_tests)
    
        def end_test(self, data, test):
            if test.status == 'PASS' and test.elapsedtime > self.max_milliseconds:
                test.status = 'FAIL'
                test.message = 'Test execution took too long.'
    
        def log_message(self, msg):
            if msg.level == 'WARN' and not msg.html:
                msg.message = '<b style="font-size: 1.5em">%s</b>' % msg.message
                msg.html = True
    

    一个限制是,修改现有的测试套件的名称或测试 情况下是不可能的,因为它已经被写入 output.xml 文件时,调用侦听器。 由于同样的原因修改了 完成了测试 end_suite 方法没有效果。

    这个API非常相似 pre-Rebot修饰符 可以使用API 修改结果报告和日志生成之前。 主要的区别是 听众修改创建的 output.xml 文件。

    测试库作为监听器

    有时它也很有用 测试库 以获得关于的通知 测试执行。 这允许它们,例如,执行特定的清理 活动时自动测试套件或整个测试执行结束。

    请注意

    这个功能是新的2.8.5机器人框架。

    注册监听器

    一个测试库可以通过注册一个侦听器 ROBOT_LIBRARY_LISTENER 属性。 这个属性的值应该侦听器的一个实例 使用。 它可能是一个完全独立的侦听器或图书馆本身 作为一个侦听器。 为了避免侦听器方法公开为关键词 后者的情况下,可以用下划线前缀。 例如,而不是使用 end_suite 或 endSuite ,它是 可以使用 _end_suite 或 _endSuite 

    下面的例子演示了使用外部侦听器以及图书馆 作为一个侦听器本身:

    import my.project.Listener;
    
    public class JavaLibraryWithExternalListener {
        public static final Listener ROBOT_LIBRARY_LISTENER = new Listener();
        public static final String ROBOT_LIBRARY_SCOPE = "GLOBAL";
        public static final int ROBOT_LISTENER_API_VERSION = 2;
    
        // actual library code here ...
    }
    
    class PythonLibraryAsListenerItself(object):
        ROBOT_LIBRARY_SCOPE = 'TEST SUITE'
        ROBOT_LISTENER_API_VERSION = 2
    
        def __init__(self):
            self.ROBOT_LIBRARY_LISTENER = self
    
        def _end_suite(self, name, attrs):
            print 'Suite %s (%s) ending.' % (name, attrs['id'])
    
        # actual library code here ...
    

    如上秒的例子已经证明,图书馆的听众 指定 监听器接口的版本 使用 ROBOT_LISTENER_API_VERSION 属性就像其他任何侦听器。

    从2.9版开始,您还可以提供任何喜欢的对象列表 实例的 ROBOT_LIBRARY_LISTENER 属性。 这将会导致所有的 注册作为监听器实例的列表。

    侦听器方法调用

    图书馆的侦听器将得到关于套件中所有事件通知 图书馆是进口的。 在实践中这意味着 start_suite end_suite start_test end_test start_keyword end_keyword log_message ,消息 方法是 在这些套件。

    如果库创建一个新的侦听器实例每次图书馆 本身就是实例化,实际使用的监听器实例将会改变 根据 测试库范围 。 除了前面列出的侦听器方法, 关闭 方法被调用时,图书馆超出范围。

    看到 监听器接口方法 上面部分的更多信息 所有这些方法。

    扩展机器人框架Jar

    额外的测试库或支持代码添加到机器人框架jar 很简单的使用 jar 命令包含在标准JDK 安装。 必须放置在Python代码 自由 目录里面 jar和Java代码可以直接放在jar的根源,根据 包结构。

    例如,添加Python包 mytestlib jar,第一次复制 mytestlib 目录下的一个目录 自由 ,然后运行 目录包含以下命令 自由 :

    jar uf /path/to/robotframework-2.7.1.jar Lib
    

    编译后的java类添加到罐子里,你必须有一个目录结构 对应于Java包结构和添加,递归 邮政编码。

    例如,添加类 MyLib.class 在包 org.test , 必须的文件 org/test/MyLib.class 你可以执行:

    jar uf /path/to/robotframework-2.7.1.jar org
  • 相关阅读:
    ie 标题写入问题
    预览图片
    form表单submit事件
    SpringGraph 20101030 11:08[转]
    flexunable to transcode image
    navicate导入和导出数据库(转)
    Flex转自新浪微博
    zk中的Datebox中得到Timestamp
    反向代理
    flash builder sdk 4[转自IYeye]
  • 原文地址:https://www.cnblogs.com/kuihua/p/5400152.html
Copyright © 2011-2022 走看看