将commandtax、scriptax、标准库和api结合在一起,创建一个强大的自动化框架。请使用starterpack快速将其他驱动程序、配置和自定义代码合并到apitax中。

apitax的Python项目详细描述


增值税

发音:ahhp ehh tax

tl;dr:代码示例位于本文档的最底部;但是,我强烈建议您通读文档以了解可能的内容。

最后,由于apitax的特性是各种交互的指数级数量,所以这里并不是所有的交互都有文档记录。尝试一下语法,学习一下语法,享受一下apitax!

它是什么

apitax是一个利用commandtax和scriptax的api自动化框架。commandtax是一种api语言,有助于快速原型强大的restapi请求。Scriptax是一种使用CommandTax的自动化语言。

更详细(更详细!)名为"为什么使用apitax"的说明位于本文档的最底部。

构建和安装

起动组件

我强烈建议您使用入门包来启动和运行apitax。它为您提供了一个文件的模板存储库,您可以对其进行更改以更好地适应您的应用程序。

apitax起始包可以在这里找到:https://github.com/apitax/starterpack

入门包的优点和功能:

  • 一套完整的工作文件,用一个命令启动apitax
  • 将apitax/core、apitax/drivers、apitax/scripts和apitax/cli集成在一起,为您提供一个全新的体验
  • 提供启动apitax/仪表板的选项
  • 完全可定制,就像您试图自己使用原始的apitax代码一样
  • Docker中的每一项服务都以一种快速的动作启动
注意:
  • starterpack使用pip和docker构建应用程序。因此,需要在用于生成这些图像的计算机上建立Internet连接。

Pip

pypi上的apitax:https://pypi.org/project/apitax/" rel="nofollow">https://pypi.org/project/apitax/

使用pip,您可以将apitax引入到您的项目中。

码头工人

Docker是部署Apitax的推荐方法。有关如何实现这一点的示例,请参见初学者包。虽然可以自己构建apitax,但只有在开发apitax时才建议这样做。

警告:apitax/core是基本的apitax图像。它不是自己部署的,必须用作使用apitax的应用程序映像的基础。有关更多详细信息,请参见入门包。

对于程序员来说:在编程语言中,把apitax映像看作是一个抽象类,由您来构建包含apitax的类。

文档hub

使用dockerfile构建自己

您可以使用提供的docker文件快速构建apitax映像。但是,此映像将无法正常工作,因为它将丢失config.txtproject.py,并且没有驱动程序。有关如何包含这些内容的详细信息,请参见初学者包。

步骤:

  • 克隆Apitax存储库
  • 建立图像:Docker Build--无缓存-我的惊人图像。
  • 运行新创建的图像:docker run-d-p 5080:5080 My Amazing Images
    • 这将在后台运行容器,要在前台运行容器,请删除-d标志。

詹金斯

  • Jenkins在这里提供:https://openrubicon.com/blue/organizations/jenkins/apitax/activity
  • 此地址将来可能会更改
  • 詹金斯平台上没有版本,他们喜欢伊利永远不会
  • 生成将定期触发或通过git推送触发
  • 在不久的将来,构建工件可能会被推送到下载服务器上
    • 只提供非依赖性版本。平均而言,这些版本的大小约为包含依赖项的版本大小的7.5%
    • 主要版本和次要版本还将具有依赖项生成功能,但是Bug和安全版本将不具有依赖项版本
    • 最好总是下载no deps版本并确保您自己下载依赖项

PIP包装说明

  • 使用powershell或bash
  • 构建包:python setup.py sdist bdist_wheel
  • 将包上载到pypi:捆绳上载dist/*-r pypi
  • 更多信息可以在这里找到:https://gist.github.com/shawnclake/759e9d09af868ef18f8c7b39d1684ad4" rel="nofollow">https://gist.github.com/shawnclake/759e9d09af868ef18f8c7b39d1684ad4

自述文件转换说明

  • 安装pandoc如果尚未安装:sudo apt get install pandoc
  • 运行命令:pandoc-o readme.docx-f markdown-t docx readme.md

从另一个目录编译antlr语法

这有时是必要的,因为antlr编译器中存在有关路径的错误

  • 下载antlr compiler.jar文件并保存到某个地方。
  • 在保存.jar的目录中,创建以下文件夹层次结构
    • 构建
    • SRC
    • 脚本
    • 日志
  • 创建一个.bat或.sh文件(取决于操作系统)并添加以下脚本:
#!/bin/bashgrammardir=~/grammar
apitaxdir=~/apitax-dev/Apitax/apitax/grammar
antlr='antlr-4.7.1-complete.jar'
java -jar $grammardir/$antlr -Dlanguage=Python3 $grammardir/src/$2
java -jar $grammardir/$antlr  -lib $grammardir/src -o $grammardir/build -listener -visitor -Dlanguage=Python3 $grammardir/src/$1
cp -r $grammardir/build/* $apitaxdir/build
cp $grammardir/src/$2$apitaxdir/src
cp $grammardir/src/$1$apitaxdir/src
  • 只要您想更改语法,就从新的~/grammar/src目录中进行更改,然后运行脚本
    • 必须将解析器和lexer语法作为参数传入bash~/grammar/run.sh ah210.g4 ahlex210.g4

文档和用法

CommandTax-数据收集、操作、使用

commandtax是rest api的一种高效、流畅的命令语言。可以将它看作一种更好的curl,它支持更好的日志记录、更好的调试和更合理的标志。

现有的

  • 脚本<;pathtosomescript>;
    • 自动执行API请求的命令序列
    • 脚本可以包含其他脚本命令,这实际上意味着脚本可以嵌套
    • 脚本按从上到下的顺序运行,如果找到嵌套脚本,则在继续执行当前脚本之前执行嵌套脚本
  • 自定义<;somecustomcommand>;
    • 处理未烘焙到实用程序中的自定义请求
    • 参数
      • --get:使用get方法
      • --post:使用post方法
      • --PUT:使用PUT方法
      • --修补程序:使用修补程序方法
      • --delete:使用delete方法
      • --url:(string)端点
      • --调试:设置调试模式
      • --敏感:设置敏感模式
      • --data post:(json字符串)任何post数据
      • --数据查询:(json字符串)任何查询参数,例如endpoint.com/something?this=queryparam
      • --数据路径:(json字符串)任何url路径变量,例如endpoint.com/users/{path_var}/show

即将推出
  • 外壳<;somecommand>;
    • 在shell中运行命令并返回shell的响应
  • 每个命令标志的可选删节语法。这些例子随时可能改变
    • --获取->;-g
    • --后->;-p
    • --放置->;-q
    • --修补程序->;-w
    • --删除->;-e
    • --url->;-u
    • --调试->;-d
    • --敏感->;-s
    • --数据发布->;-z
    • --数据查询->;-x
    • --数据路径->;-c

Scriptax-控制流、范围界定和自动化

scriptax是一种api优先的自动化语言。Scriptax不是一种通用语言,而是一种专门为优化基于API的环境中的自动化而设计的语言。

语言

  • ct(必需:"\<;somecommand\>;"){%}
    • 执行命令税
    • 在分析行的过程中执行命令并返回其响应
    • 支持异步回调
  • get(必需:"\<;somecommand\>;",可选:{dataobj},可选:param1…n){%}
    • 执行GET请求
    • 数据对象采用与commandtax自定义数据相对应的可选键:post、query、path、header
    • 返回结果
    • 支持异步回调
  • put(必需:"\<;somecommand\>;",可选:{dataobj},可选:param1…n){%}
    • 执行PUT请求
    • 数据对象采用与commandtax自定义数据相对应的可选键:post、query、path、header
    • 返回结果
    • 支持异步回调
  • 修补程序(必需:"\<;somecommand\>;",可选:{dataobj},可选:param1…n){%}
    • 执行修补程序请求
    • 数据对象采用与commandtax自定义数据相对应的可选键:post、query、path、header
    • 返回结果
    • 支持异步回调
  • post(必需:"\<;somecommand\>;",可选:{dataobj},可选:param1…n){%}
    • 执行POST请求
    • 数据对象采用与commandtax自定义数据相对应的可选键:post、query、path、header
    • 返回结果
    • 支持异步回调
  • 删除(必需:"\<;somecommand\>;",可选:{dataobj},可选:param1…n){%}
    • 执行删除请求
    • 数据对象采用与commandtax自定义数据相对应的可选键:post、query、path、header
    • 返回结果
    • 支持异步回调
  • {dataobj}
    • 包含命令可选参数的json对象,例如:
      • auth-用于此请求的凭据集
      • post-json-一个详细说明任何post参数的对象
      • query-json-一个详细说明任何查询参数的对象
      • path-json-一个详细说明任何路径参数的对象
      • driver-用于此请求的驱动程序
      • strict-默认值:true-如果请求返回状态代码>;299或<;200,则整个脚本是否应失败
  • 新的openstacknetworks(可选=参数);
    • 创建openstacknetworks脚本的新实例
    • 可选参数应与信号线相对应
  • \<;attributes\>;\<;methodname\>;(可选=参数){}
    • 向当前脚本添加方法
    • 属性可以是apiscript
  • \<;methodname\>;(可选=参数);
    • 使用可选参数执行方法
  • 异步
    • 在任何支持异步的关键字前面添加此关键字,以便在新线程中运行操作
    • 也可以在方法语句前面使用:api async getnetworks(){}
    • 异步获取("http://placeholderjson.com/users",{}){%}
    • somevar=async get("http://placeholderjson.com/users",{}){%}
    • 在将请求的结果存储到变量中之前执行回调
    • 变量将用一个新的线程实例初始化,一旦线程完成,它将被替换为通过e回拨
  • 等待\<;某个可选变量\>;;
    • 指定变量时,请等到该变量指定的异步执行完成。
    • 如果未指定变量,请等到当前脚本中所有打开的线程都完成后再继续
    • 也可以在使用方法调用时使用:result=await openstack.getnetworks();
  • {%%};
    • 回调块
    • 内容将在单独的作用域中执行,通常只能访问结果变量
  • str()
    • 转换为字符串
  • int()
    • 强制转换为舍入整数
  • dec()
    • 转换为浮动
  • bool()
    • 转换为真/假
  • list()
    • 强制转换为列表
    • 仅适用于字符串
  • dict()
    • 转换为字典
    • 在列表、字符串、int、decs上工作
  • \
    • 返回变量的长度
    • 处理字符串、列表、词典(仅返回顶级计数)
  • \$
    • 转义标签名称,以便可以使用与语言关键字相同的标签
  • 代码>!< /代码>
    • 将此项添加到语句的开头时,不会记录或打印该行的执行情况
  • \@
    • 返回变量的反射
  • 扩展(\<;somescriptpath\>;);
    • 通过扩展另一个脚本向脚本添加多态性
  • 删除(\<;somevar\>;)
    • 从当前作用域中删除somevar
  • 返回\<;选项变量\>;
    • 立即退出脚本并返回一些表达式
  • 选项(可选=参数)
    • 用于指定脚本的选项
  • sig(param1Required,thisparam=isoptional,thisOneIsRequired);
    • 为脚本指定参数
  • 如果(条件){}
    • if语句
  • while(条件){}
    • while循环
  • 对于\<;existingvar\>;{}中的\<;somevar\>;
    • 按顺序循环浏览列表中的每个项目
  • 用于\<;someNumber\>;{}中的\<;somevar\>;
    • 从1循环到someNumber并将someVar设置为当前迭代
  • 每个\<;somelist\>;{%};
    • 将列表设置results循环到当前项并在独立回调中执行指令
  • \<;somevar\>;=\<;someexpression\>;
    • 设置变量
    • 支持表达式、字符串、数字、布尔值、字典、列表和CommandTax响应
  • "这是一个字符串{{somevar}"
    • 注入变量的内容
    • 可能有一些花哨的东西,例如:set newvar=ct({{somevar}})
  • \<;someexpression\>;
    • 注入表达式
    • 在这种情况下,必须包括箭头括号
  • 从drivername导入somescript作为somename
    • 这将导入要在当前脚本中使用的其他scriptax
    • from和as是可选的
  • 验证(\<;someauthobject\>;)
    • 设置当前执行脚本的默认身份验证
  • 登录(用户名{{someuser},密码{{somepass},令牌{{sometoken},驱动程序{{somedriver},额外的{{{somejsonobj})
    • 登录中的每个参数都是可选的。所需参数通过驱动器t定义o由login命令使用。此驱动程序可以是默认脚本驱动程序,也可以是登录参数中指定的驱动程序。
    • 返回auth对象
    • 可以直接与auth一起使用,例如:auth login(username=test,password=test123);
  • 端点(someendpointname@somedriver)
    • 使用driversgetcatalog方法,将返回在指定驱动程序的目录中找到的端点
    • 这可以直接与url一起使用,例如:url endpoint('keystone@openstack')
  • url(\<;someurl\>;)
    • 将当前工作URL设置为在进一步的CommandTax中使用
  • log("将一些输出记录到控制台日志文件")
    • 支持表达式
  • /一些注释
    • 内联注释
  • /*一些跨越多行的注释*/
    • 阻止注释

范围

在Scriptax中,没有全局作用域。每一条数据都属于一个范围。Scriptax中有许多不同的作用域类型:

  • 脚本范围-这些是可以在整个脚本中访问的符号。例如SIG参数或脚本级变量。
  • 方法范围-这些是可以从方法中访问的符号。当然,这个作用域继承自脚本作用域。
  • 流/块范围-这些是流块中可访问的符号,如if语句或循环。当然,这个作用域继承自脚本作用域。
  • 回调作用域-这些是可在回调中访问的符号。通常,可以访问结果变量以及通过(可选=参数)->;{%}语法传入的任何其他值。通常回调作用域是只读的,对其中任何变量所做的任何更改都将仅在回调作用域内更改。唯一的例外是result变量,该变量通常用于以返回样式返回数据。

脚本方法流/块作用域都将继承其父作用域。回调另一方面,作用域是完全隔离的,必须明确告知哪些符号允许进入,并且只能以只读形式进入。

架构

  • 在scriptax中,每个文件都被视为一个对象。换句话说,在其他编程和脚本语言中,每个文件都类似于
  • scriptax中的实例只确保脚本作用域中的变量是唯一的。
  • scriptax中的方法本质上是静态的。换句话说,方法不是每个实例唯一的,可以在脚本本身或脚本实例上调用。如果通过脚本本身调用方法并尝试使用脚本范围变量,则会抛出错误。

结构

scriptax有一个必须遵循的结构,否则将抛出错误或脚本将完成错误。

脚本的前几行专门用于global_语句。这些语句包括extendssignatureoptions,最后是imports。Scriptax对于global_语句非常严格,因此它们甚至必须是有序的。如果选择使用extends它必须是文件中的第一个语句,没有例外。如果选择使用signature它必须在extends之后立即出现,但如果不使用extendssignature必须是文件中的第一个语句,以此类推。全局语句的顺序如下:

  1. 扩展
  2. 签名
  3. < >鳕鱼E>选项
  4. 导入

虽然扩展签名选项在脚本文件中只应出现0或1次,但导入在文件中可能出现0..n次。

全局语句之后请随意使用您认为合适的任何非全局语句。

Scriptax陷阱/提示/技巧

  • 访问由sig定义的参数时应该这样做:param.firstparam其中firstparam是参数的名称
  • 为了与apitax/dashboard和apitax/cli实现最佳兼容,请在每个scriptax文件开头加上sig行(如果是nesecary)。
  • 可以通过点表示法使用数组
    • 设置somevar.1=num1
    • 设置somevar.2=num2
    • 设置值。<;counter>;=num3
    • 执行此操作时,变量的第一个用法必须是somevar="{}"或作为该对象一部分的索引。否则将导致抛出错误。

最佳实践
  • await;结束每个脚本,以确保所有异步请求在返回父脚本之前都已完成。
    • await;结尾,后跟return\<;somevar\>;;也可以接受
  • 当不再需要未使用的变量时,从根作用域中删除它们del\<;somevar\>;
  • 仅从下标导出/返回必需的变量
  • 保持根范围尽可能干净
  • 脚本应该是严格遵循srp的小型容器化代码。
    • 把脚本想象成乐高积木,最终你可以把它们组合在一起,打造出真正酷的东西
  • Scriptax是一种灵活、宽容和强大的语言
    • 四处玩耍看看你能做什么和不能做什么。边缘案例太多,无法明确列出。

即将推出
  • 时间方法

命令行接口(cli)

  • 您可以直接从cli激活apitax,而无需包装包
  • 运行在根apitax目录中找到的tests.py文件,并提供以下参数
    • --cli:(可选)快速选择cli模式
    • --api:(可选)快速选择web服务器模式
    • --debug:(可选)输出请求响应状态、标题和正文
    • -u<;input>;:(可选)指定身份验证用户名-仅适用于cli模式
    • -p:(可选)立即请求输入密码。如果指定了-u,但未指定,则应用程序将请求一组新的凭据进行身份验证。但是,它将对进一步请求中的任何用户名字段使用-u值。这允许某人以管理员身份进行身份验证,但可以运行适用于其他用户的命令。
    • -r<;input>;:(可选)请求-仅适用于cli模式
    • -s<;input>;:(可选)运行由文件路径<;input>;指定的请求脚本,所有这些请求的身份验证都由-u&;-p指定

模式

  • cli:从命令行发出请求
  • api:启动api服务器

配置

  • 示例配置文件存储在repo的根目录中

支持的身份验证

  • 身份验证是为http basic和基于令牌的身份验证预先构建的
  • 在自定义场景中,身份验证主要由开发人员负责
    • 驱动程序文件有助于满足此要求

驱动程序和插件

**此操作已重做,需要更新配置**

  • 驱动程序和插件用于将apitax的功能扩展到任意api
  • 驱动程序必须通过project.py文件动态添加到应用程序中。请参见API税收/入门包,例如如何做到这一点。

Apitax的实例:

命令税示例
custom --get --url <someEndpoint>
custom --get --url <someEndpoint> --data-param '{"is_domain": true}'
custom --post --url <someEndpoint> --data-post '{"title": "im the title"}'
custom --put --url <someEndpoint> 
custom --patch --url <someEndpoint>
custom --delete --url <someEndpoint> 
custom --get --url <someEndpoint> --data-param '{"user.id": "1"}'
custom --get --url <someEndpoint>/with/some/{ohyear}/url/params/{981} --data-param '{"is_domain": true}' --data-path '{"ohyeah":"no", "981": "yes"}'

脚本~/path/to/my/script.ah

scriptax示例
// async-tests.ah

url "https://jsonplaceholder.typicode.com";

bob = [];
threads = [];

/*each get("/users", {})
{%
	url "https://jsonplaceholder.typicode.com";
	threads[] = async get("/posts", {
          	"query": {
                "userId": result.id,
            },
        }) {%
        	log("The user has these posts: " + result);    
        %};
%};*/

for user in get("/users", {})
    threads[] = async get("/posts", {
            "query": {
                "userId": user.id,
            },
        }) {%
        log("The user has these posts: " + result);
        //bob[] = result;
    %};

await threads;

del threads;

script("apitax/grammar/scripts/base.ah");

log("yo man im at the end");


/*for user in get("/users", {})
    threads = async get("/posts", {
            "query": {
                "userId": user.id,
            },
        }) {%
        log("The user has these posts: " + result);
        bob[] = result
    %};

//bob[] = "hey";

for t in threads
	await t;

log(bob);

log("Im quite confused");*/

// base.ah

url "https://jsonplaceholder.typicode.com";
for user in get("/users")
{
    /*result = get("/posts", {
        "query": {
            "userId": user.id,
        }
    });
    log("The user has these posts: " + result);*/

    log("the user has ID: " + user.id);

    async get("/posts", {
            "query": {
                "userId": user.id,
            }
        }) {%
        log("The user has these posts: " + result);
    %};

}  

response = post("/posts", {
    "post": {
        "title":'foo',
        "body":'bar',
        "userId":1
    }
});

log(script("apitax/grammar/scripts/jen.ah", {}, "i am parameter 1", "i am parameter 2"));

//response = ;

log("Please " + ct("tests my script", {}, "i should be a parameter"));


testlist = ["one", "two", 'three', ["a", 'b', 'c', 'd'], {"test": "failed", "yes": "no"}];

log(#testlist.0);


/*async ct("some command execution")
{
log("some integrated callback");
}

async ct("some command execution");

status = async ct("some command execution");

await status;

status = [firstAsync, secondAsync];
await status;

async bobo in get("/users")
{
    log("Async callback: " + bobo);
}*/

async get("/users");



somelabel = async get("/users")
{%
    log("I am an optional callback");
%};
//anotherRequest0 = async get("/users");
//anotherRequest1 = async get("/users");
//anotherRequest2 = async get("/users");

await somelabel;

log("i am that label" + somelabel);


get("/users") {%

log(result);

%};

async get("/users") {%

log(result);

%};


for iter in 10 {

    async get("/posts", {
            "query": {
                "userId": iter,
            }
        }) {%
        log("The user has these posts: " + result);
    %};

}

log("here is where the magic happens");

get("/posts", {
        "query": {
            "userId": 5,
        }
    }) {%
    log("The user has these posts: " + result);
%};


await;

// jen.ah

options dict('{"params": ["name", "game"]}');
answer=2+2;
name "quinn";

set qwer = "im in jens script";


export qwer;

//export ct("script apitax/grammar/scripts/shawn.ah");

set iam.hope.this.works = ct("custom --get --url https://jsonplaceholder.typicode.com/users");

export iam;

set test = "hello";

//return '{"cool": "beans"}';

log(params.passed.0);

log(params.passed.1);

log(params.name);

log(params.game);

log(2+2);

return params.passed.1;

//return "test";


await;

// my_script.ah


options dict('{"params": ["first"]}');

log("I got here");

log(params.first);

return "work";


await;

为什么使用apitax

假设一个后端只作为一个实体存在,它什么也不做,直到被告知要做某事。

如果是这样的话,我们还假设除了restful api之外,后端没有接口。

好吧,假设我们要建立一个前端,它将列出每个用户最近10篇文章。

我们可以这样做的一种方法是发出一个api请求来检索用户列表。然后,在javascript中,我们可以遍历用户列表,对于每个用户,我们都可以发出api请求以获取他们最近的帖子。在javascript中,我们可以一起编译这个用户列表并显示出来。

听起来很简单-除了我们如何利用异步代码加速这个过程。我们开始引入各种嵌套回调,javascript中的desync很复杂,很难进行错误测试,当我们将这些代码的位和片段复制到不同的文件/页面以不同的方式列出不同类型的数据时,我们开始崩溃。

我们可以通过创建巨型api类来解决一些枯燥的问题,这些类为每种类型的调用都提供了helper方法,但是仍然会变得一团糟。

我们想要的是专注于前端开发,而不是api请求垃圾。通过这样做,我们将前端架构的srp作为一个整体来实施。前端代码的大部分应该专用于显示数据、获取输入和显示用户对其输入的响应。不应该有成千上万行的人调用api并试图组织数据。必须有一个更简单的方法,对吧?

如果前端只有4个不同的api请求。1用于身份验证,1用于获取终结点目录,1用于获取系统状态,最后1用于促进双向数据的传输。这就是apitax/commandtax发挥作用的地方。我们现在有一个端点来发送请求,该请求的有效负载是commandtax。

太好了!现在,我们可能只需要一些helper字符串常量来存储常用的命令,而不是到处都是一堆helper方法。已经更干净更可行了。但是,这仍然不能解决我们的干问题,srp,或回调和desync地狱,我们将面临从不得不连续提出几个请求来完成一项任务。

输入:scriptax。现在,我们中的任何人都可以创建一些自包含的子模块文件来为您执行这些顺序请求。这些文件称为脚本。一个脚本可能负责获取遵循某些参数集的用户列表,另一个脚本可能调用该用户脚本,然后使用返回的响应,它可以获取每个用户的帖子列表并返回它们。

好了,现在我们的前端只有一个命令行,它正在执行一个脚本。如果脚本写得好,就不再有回调地狱,srp被保留,dry被强制执行,返回给我们的数据将已经是一个非常可行的格式。kaboomskies,您刚刚为自己保存了24行难以调试的javascript代码,相反,它是一行代码,以一种可行的格式返回数据

将commandtax、scriptax、标准库和api结合在一起,创建一个强大的自动化框架。请使用starterpack快速将其他驱动程序、配置和自定义代码合并到apitax中。

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
正则表达式使用Java从服务器截断文本   micronaut微服务的java内存消耗   如果私有函数需要相同的输入,java应该在公共函数中显式执行异常检查   为什么我们在java中使用抽象类和抽象方法   Java中接受外来字母的字符串?   cordova Android:ClassNotFoundException,包括ZXing   通过LiveData observer向特定索引添加项时出现java IndexOutOfBoundsException   jsp Java从两个源调用一个servlet   java如何设置网格布局中按钮的位置?   java HashMap返回方法   java JDK错误版本   java如何将现有类集成到新的Swing项目中   java如何在扫描程序位于输入端时使for循环停止   java正则表达式匹配空白表   java组织。格拉德尔。工具。BuildException:设置的代码长度无效   JList中的swing Java格式化字符串   javabeans如何将JavaBean属性映射到另一个名称以进行输出?   ajax请求后的java Rerender RichFaces错误消息