仓酷云

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 420|回复: 8
打印 上一主题 下一主题

[学习教程] ASP网页编程之“穿越”防火墙的XML手艺

[复制链接]
灵魂腐蚀 该用户已被删除
跳转到指定楼层
楼主
发表于 2015-1-16 22:26:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
ASP由于使用了COM组件所以它会变的十分强大,但是这样的强大由于WindowsNT系统最初的设计问题而会引发大量的安全问题。只要在这样的组件或是操作中一不注意,哪么外部攻击就可以取得相当高的权限而导致网站瘫痪或者数据丢失;程序员大概会常常碰着如许的事变:创建一个servlet使用程序,它与公司的数据库相毗连,为客户供应一种特定的服务,这个使用程序遭到一个壮大的考证机制回护,全球有不计其数的客户都在利用它。如今就呈现了一个成绩:当使用程序处在公司的防火墙以外时,你将怎样从使用程序供应用户对数据库的会见?你晓得,收集办理员是不会专门为你的使用程序与数据库相毗连而翻开一个特别端口的。

HTTP地道手艺和XML
怎样超出防火墙与客户/服务器使用程序相毗连这个成绩已困扰程序员好久了。在多半情形下,一个公司的防火墙老是尽量少地翻开端口。一样平常情形下,你可以利用的独一端口就是80,这也就是Web所利用的端口。

办理这个成绩的办法就是利用HTTP地道手艺(HTTPtunneling)。这个办法起首将哀求包装在一个HTTPPOST哀求中,然后这个哀求再由一个在防火墙内的Web服务器上的CGI使用程序(比方一个servlet)来处置。

Servlet恢回复始的哀求,实行它,然后将了局拔出到HTTP呼应流中。防火墙将这类互相感化注释为对一个Web页面的惯例哀求,并同意对它持续举行处置。这就象特洛伊木马一样:看起来是一个一般的哀求,但个中埋没着意料不到的负载。

下一个成绩是怎样对哀求举行格局化?固然,利用XML是将这些负载送进一个HTTP哀求中往的最好选择。这个看法很有首创性,HTTP之上的XML是一个抢手的新兴范畴,一些新的划定规矩正在编写中,未来能够成为散布式使用程序的尺度通信协定。个中,复杂工具会见协定(SOAP)是最失掉公认的。

遗憾的是,如今还没有一个不乱实行的SOAP供我们利用,今朝所能找到的最好的一个来自Apache团体,可是它只撑持复杂的前往范例。因而,它关于我们的项目是没有效的。可是这也不错,这意味着我们能够提出本人的HTTP上的XML的协定,而且借此来进修个中包括的观点。
观点
如今我们来创建一个复杂的框架布局(framework),它将HTTP上的XML作为基础的通信战略,从而让我们可以创立一套服务,并且使得这些服务从散布在Internet上五湖四海的桌面使用程序都能够举行会见。

起首,我们必要创建一般哀求和呼应的语法。哀求看起来是如许的:

<?xmlversion=1.0encoding=utf-8?>
<http-request>
<requestType>
[typeofrequest]
</requestType>
<request>
[Applicationspecificrequest.ThiswillbeanXMLElment]
</request>
</http-request>

呼应看起来是如许的:

<?xmlversion=1.0encoding=utf-8?>
<response>
<responseMessage>
[theresponseMessage]
</responseCode>
<responseCode>
[anapplicationspecificreturncode.]
</responseCode>
<response>
[Applicationspecificrequest.ThiswillbeanXMLElement]
</response>
</http-response>

为了了解这个框架布局面前的观点,我们要编写一个使用服务例程:一个复杂的数据库服务,它对任何SQL语句举行处置,而且将了局作为一个向量来前往。哀求的细节,也就是哀求元素所包括的XML标志十分复杂,以下:

<sql-statement>
[TheSQLstatementtobeexecuted]
</sql-statement>
呼应了局是如许的:
<result-set>
</result-count>
[thenumberofrowsintheresultset]
</result-count>
<row>
<colname=name>
[thevalue]
</col>
?
</row>
?
<result-set>

HTTPService是一个servlet,它呼应一个POST哀求,恢复XML负载,并利用它来创立一个ServiceRequest例示。然后,依据哀求的范例,将哀求交给HttpServiceHandler笼统类的一个特定子类。Handler类实行哀求,在ServiceResponse的一个例示中存储了局,然后将这个了局发送回客户端使用程序。

经由过程依照常规为服务处置器类定名,我们能够使用Java的映象功效来创立处置器类的一个例示,这个处置器类仅仅是创建在ServiceRequest工具的服务范例属性的基本上。这就作废了HttpService和一切服务处置器类之间的依附性,从而意味着当我们增添一个新服务时,不再必要改动HttpService类。

在我们这个例子中,服务的范例是DBService,因而我们将创立HttpServiceHandler的一个子类,叫做DBServiceHandler。在HttpService中,我们利用以下代码:

StringclassName=PACKAGE_NAME+"."+request.getRequestType()+"Handler";
HttpServiceHandlerhandler=Class.fromName(className).newInstance();
handler.handleRequest(request);

一个HttpServiceHandler子类必要实行一个办法processRequest(),它必要取一个ServiceRequest工具,然后前往一个ServiceResponse工具。这个办法是在handleRequest办法的过程当中由子类挪用的:

PublicvoidhandleRequest(ServiceRequestrequest)
{
Serviceresponseresponse=processRequest(request);
SendResponse(response);
}

这是利用Template(模板)办法形式的一个典范例子,在这个过程当中,笼统超类挪用在一个子类中实行的办法。

ServiceRequest类将服务特定命据存储为一个XML文档。这个类由会见者来设置和猎取哀求范例,它另有办法来处置哀求的细节。getRequest()办法前往包括在哀求标志中的XML节点,setRequest()办法则用一个重生成的哀求来掩盖本来的哀求。这个类还利用两个factory办法,创立新的元素和文本节点,同意开辟职员天生新的哀求。ServiceResponse类以一种十分复杂的办法来处置哀求的细节。

固然这两个类同意我们对一切范例的哀求和呼应举行处置,可是开辟职员也必需要懂得每一个哀求的特别语法。开辟职员不克不及对哀求的格局是不是准确举行任何确认。

为了简化这个历程,我们将创立ServiceRequest和ServiceResponse的子类,它们分离叫做DBServiceRequest和DBServiceResponse,它们都有处置服务特定细节的办法。比方,DBServiceRequest有设置和猎取SQL语句的办法,同时DBServiceResponse有设置和猎取了局记数值和了局设置矢量的办法。

服务是用HttpServiceClient类来会见的。在客户端使用程序中,有以下的代码:

HttpServiceClientclient=newHttpServiceClient(serviceURL);
DBServiceRequestrequest=newDBServiceRequest();
request.setSqlStatement(statement);
DBServiceResponseresponse=newDBServiceResponse(client.executeRequest(request));

个中服务的URL是如许的:

http://myHost/servlet/httpservice.HttpService.

细节
下面我们已看到了框架布局中的一切元素,如今来看看那些风趣的细节。起首让我们来注重一下协定层。我们应当怎样创立包装XML负载的HTTPPOST哀求?我们应当怎样处置HTTP呼应?

HTTP哀求是尺度化的、基于ASCII的、与一个Web服务器的socket通信。这里有一个例子:

POST/servlet/
httpService.HttpserviceHTTP/1.0
Host:localhostt:80
Content-Type:text/xml
Content-Length:248
<?xmlversion=1.0encoding=utf-8?>
<http-request>
<requestType>DBService</requestType>
<request>
<sql-statement>
SELECT*FROMMyTable
</sql-statement>
</request>
</http-request>

来自Web服务器的呼应以下所示:

HTTP/1.0200OK
Date:Fri,24Nov200016:09:57GMT
Status:200
Servlet-Engine:TomcatWebServer/3.1(JSP1.1;
Servlet2.2;Java1.3.0;Windows20005.0x86;
java.vendor=SunMicrosystemsInc.)
Content-Type:text/xml
Content-Length:726
Content-Language:en
<?xmlversion=1.0encoding=utf-8?>
<http-response>
<responseMessage>OK</responseCode>
<responseCode>200</responseCode>
<response>
<result-set>
</result-count>2</result-count>
<row>
<colname=col1>value11</col>
<colname=col2>value12</col>
</row>
<row>
<colname=col1>value21</col>
<colname=col2>value22/</col>
</row>
<result-set>
</response>
</http-response>


上面的代码显现了HttpServiceClient类的实行,它将处置HTTP哀求的一切细节。你能看到,一旦你懂得了那些哀求的正确格局,这就是一个十分复杂的历程:

publicclassHttpServiceClient
{
privatestaticfinalStringHTTP_VERSION="1.0";
privatestaticfinalStringHTTP_POST_REQUEST="POST";
privatestaticfinalStringHEADER_HOST="Host";
privatestaticfinalStringHEADER_CONTENT_TYPE="Content-Type";
privatestaticfinalStringXML_MIME_TYPE="text/xml";
privatestaticfinalString
HEADER_CONTENT_LENGTH="Content-Length";
privatestaticfinalintDEFAULT_PORT=80;

privateStringserviceUrl;
privateintreturnCode;
privateStringreturnMessage;
privateReaderresponsePayload;

publicHttpServiceClient(StringserviceUrl)
{
this.serviceUrl=serviceUrl;
}

publicServiceResponseexecuteRequest(ServiceRequestrequest)
throwsHttpServiceException
{

try
{
Stringdata=request.serializeRequestToString("utf-8");
postRequest(data);

//checkforfailures
if(returnCode!=200)
thrownewHttpServiceException(returnMessage);

InputSourcesource=
newInputSource(responsePayload);
DOMParserparser=newDOMParser();
parser.parse(source);
ServiceResponseserviceResponse=
newServiceResponse(parser.getDocument());

StringtheResponse=
serviceResponse.serializeResponseToString("utf-8");
System.err.println(theResponse);

returnserviceResponse;

}
catch(Exceptionex)
{
ex.printStackTrace(System.err);
thrownewHttpServiceException(ex.getMessage());
}
}


privatevoidpostRequest(Stringpayload)
throwsHttpServiceException
{
PrintWriterout=null;
BufferedReaderin=null;


URLurl=null;
try
{
url=newURL(serviceUrl);

//Noport?usedefaultport80
intport=url.getPort()<0?DEFAULT_PORT:url.getPort();

Socketsoket=newSocket(url.getHost(),port);
out=newPrintWriter(soket.getOutputStream());

in=newBufferedReader(newInputStreamReader(soket.getInputStream()));
}
catch(Exceptionex)
{
thrownewHttpServiceException("erroropeningsocket:"+ex.getMessage());
}

out.print(HTTP_POST_REQUEST+""+url.getFile()+"HTTP/"+HTTP_VERSION+"
");
out.print(HEADER_HOST+":"+url.getHost()+:+url.getPort()+"
");
out.print(HEADER_CONTENT_TYPE+":"+XML_MIME_TYPE+"
");
out.print(HEADER_CONTENT_LENGTH+":"+payload.length()+"
");
out.print("
");
out.print(payload);
out.print("

");
out.flush();

try
{
StringstatusLine=in.readLine();
System.err.println(statusLine);
parseStatusLine(statusLine);
}
catch(Exceptionex)
{
thrownewHttpServiceException("errorparsingHTTPstatusline:"+ex.getMessage());
}

//Iwillignorealltheheadersandkeepreading
//untilIgetanemptyline
try
{
StringheaderLine=null;
while((headerLine=in.readLine())!=null)
{
if(headerLine.length()==0)
break;
}
}
catch(Exceptionex)
{
thrownewHttpServiceException("errorreadingHTTPheaders:"+ex.getMessage());
}

//whatremainsoftheinputStreamismypayload
responsePayload=in;

}

privatevoidparseStatusLine(StringstatusLine)
throwsException
{
StringTokenizerst=
newStringTokenizer(statusLine);

//thisistheHTTPVersion
st.nextToken();

returnCode=Integer.parseInt(st.nextToken());

StringBufferretMessage=newStringBuffer();

while(st.hasMoreTokens())
{
retMessage.append(st.nextToken());
if(st.hasMoreTokens())
{
retMessage.append("");
}
}

returnMessage=retMessage.toString();

}

}


Web服务器承受了HTTP哀求后,它就创立一个HttpServiceservlet的新例示,接着挪用doPost()办法,在HttpServletRequest和HttpServletResponse工具中传送。然后这个servlet就恢复XML负载,而且创立ServiceRequest类的一个例示,最初将其转交给准确的处置器:

Documentdom;
DOMParserparser=newDOMParser();
InputSourceinput=newInputSource(request.getInputStream());
parser.parse(input);
dom=parser.getDocument();
ServiceRequestserviceRequest=newServiceRequest(dom);
StringclassName=PACKAGE_NAME+"."+request.getRequestType()+"Handler";
HttpServiceHandlerhandler=Class.fromName(className).newInstance();
handler.handleRequest(request);


上面的代码显现了DBServiceHandler类的实行情形,这个类创立数据库毗连、实行查询而且天生DBServiceResponse工具。一样,要注重这个历程十分复杂,由于很多庞大的成绩都埋没在ServiceResponse和ServiceRequest类及子类的前面了:

publicclassDBServiceHandlerextends
HttpServiceHandler

{
publicServiceResponseprocessRequest(ServiceRequestreq)
throwsHttpServiceException
{
DBServiceRequestrequest=newDBServiceRequest(req);

Stringsql=request.getSqlStatement();
DBServiceResponseresponse=newDBServiceResponse();
Connectionconnection;

try
{
Class.forName("oracle.jdbc.driver.OracleDriver");
StringconnectionString="jdbc:oracle:thin:@fender.openport.com:1521:iplp";
connection=DriverManager.getConnection(connectionString,"op1","op1");

}
catch(ClassNotFoundExceptionex)
{
ex.printStackTrace(System.err);
response.setResponseCode(400);
response.setResponseMessage("Oracledrivernotfound");
returnresponse;
}
catch(SQLExceptionex2)
{
ex2.printStackTrace(System.err);
response.setResponseCode(400);
response.setResponseMessage("CouldNotConnectToDatabase!");
returnresponse;
}

StringtheSql=sql.trim().toUpperCase();
ResultSetresultSet;

try
{
Statementstatement=
connection.createStatement();

if(theSql.startsWith("SELECT"))
{
resultSet=statement.executeQuery(theSql);

VectortheResults=parseResultSet(resultSet);
response.setResultsCount(theResults.size()-1);
response.setResultSet(theResults);
}
else
{
statement.executeUpdate(theSql);
response.setResultsCount(-1);
response.setResultSet(newVector());
}

}catch(SQLExceptionex)
{
response.setResponseCode(400);
response.setResponseMessage(ex.getMessage());
returnresponse;
}

response.setResponseCode(200);
response.setResponseMessage("OK");

Stringres=response.serializeResponseToString("utf-8");
System.out.println(res);

returnresponse;
}
?
}


鄙人面的代码中,你能看到ServiceRequest和DBServiceRequest的实行。请注重跟着DBService-Request还供应了一个分外的机关器,它将ServiceRequest作为一个自变量。这就同意我们把原始哀求的XML文档作为以后文档来利用,从而向现有的数据供应一个分外的使用程序独有的界面:

publicclassServiceRequest

{
publicfinalstaticStringREQUEST_TYPE_TAG_NAME="requestType";
publicfinalstaticStringREQUEST_TAG_NAME="request";
publicfinalstaticStringROOT_TAG_NAME="http-request";

protectedDocumentdom;

publicServiceRequest(Documentrequest)
{
dom=request;
}

publicServiceRequest()
{
dom=newDocumentImpl();
initializeRequest();
}

//initializesanemptyrequest
privatevoidinitializeRequest()
{
Elementroot=dom.createElement(ROOT_TAG_NAME);
dom.appendChild(root);

ElementeRequestType=
dom.createElement(REQUEST_TYPE_TAG_NAME);
eRequestType.appendChild(dom.createTextNode(""));

root.appendChild(eRequestType);

ElementeRequest=
dom.createElement(REQUEST_TAG_NAME);
root.appendChild(eRequest);
}

publicStringgetRequestType()
throwsHttpServiceException
{
try
{
returngetTextAttribute(REQUEST_TYPE_TAG_NAME);
}
catch(Exceptionex)
{
ex.printStackTrace(System.err);
thrownewHttpServiceException("InvalidRequestFormat.");
}

}

publicvoidsetRequestType(StringrequestType)
throwsHttpServiceException
{
try
{
setTextAttribute(REQUEST_TYPE_TAG_NAME,requestType);
}
catch(Exceptionex)
{
ex.printStackTrace(System.err);
thrownewHttpServiceException("InvalidRequestFormat.");
}

}

publicNodegetRequest()
throwsHttpServiceException
{
try
{
Noderequest=
((NodeList)dom.getElementsByTagName(REQUEST_TAG_NAME)).item(0);

returnrequest.getFirstChild().cloneNode(true);

}
catch(Exceptionex)
{
ex.printStackTrace(System.err);
thrownewHttpServiceException("InvalidRequestFormat.");
}
}

publicElementcreateElementNode(StringelementName)
{
returndom.createElement(elementName);
}

publicTextcreateTextNode(Stringvalue)
{
returndom.createTextNode(value);
}

publicvoidsetRequest(Noderequest)
throwsHttpServiceException
{

try
{
NoderequestElement=
((NodeList)dom.getElementsByTagName(REQUEST_TAG_NAME)).item(0);
NodeoldRequest=
requestElement.getFirstChild();

if(oldRequest!=null)
requestElement.removeChild(oldRequest);

requestElement.appendChild(request);
}
catch(Exceptionex)
{
ex.printStackTrace(System.err);
thrownewHttpServiceException("InvalidRequestFormat.");
}
}

publicbyte[]serializeRequestToByteArray(Stringencoding)
throwsHttpServiceException
{
try
{
returnserializeDOM(encoding).toByteArray();
}
catch(Exceptionex)
{
ex.printStackTrace(System.err);
thrownewHttpServiceException("Errorduringserialization");
}
}

publicStringserializeRequestToString(Stringencoding)
throwsHttpServiceException
{
try
{
returnserializeDOM(encoding).toString();
}
catch(Exceptionex)
{
ex.printStackTrace(System.err);
thrownewHttpServiceException(
"Errorduringserialization");
}
}

privateByteArrayOutputStreamserializeDOM(Stringencoding)
throwsHttpServiceException
{
try
{
ByteArrayOutputStreambytes=
newByteArrayOutputStream(4096);
PrintWriterout=newPrintWriter(newOutputStreamWriter(bytes,encoding),true);
OutputFormatof=
newOutputFormat(dom,encoding,true);
XMLSerializerserializer=newXMLSerializer(out,of);
serializer.serialize(dom);
out.close();

returnbytes;
}
catch(Exceptionex)
{
ex.printStackTrace(System.err);
thrownewHttpServiceException("Errorduringserialization");
}
}

protectedStringgetTextAttribute(Stringname)
{
NodetextAttributeNode=((NodeList)dom.getElementsByTagName(name)).item(0);
NodetextAttribute=textAttributeNode.getFirstChild();
if(textAttribute.getNodeType()==Node.TEXT_NODE)
returntextAttribute.getNodeValue();
else
returnnull;
}

protectedvoidsetTextAttribute(Stringname,Stringvalue)
{
if(value==null)
value="";
NodetextAttributeNode=((NodeList)dom.getElementsByTagName(name)).item(0);
NodetextAttribute=
textAttributeNode.getFirstChild();
textAttribute.setNodeValue(value);

}
}

publicclassDBServiceRequestextendsServiceRequest
{

publicfinalstaticStringSERVICE_NAME="DBService";

publicfinalstaticStringSQL_STATEMENT_TAG_NAME="sql-statement";

publicDBServiceRequest()
{
super();
initializeParameters();
}

publicDBServiceRequest(Documentrequest)
{
super(request);
}

publicDBServiceRequest(ServiceRequestrequest)
{
dom=request.dom;
}

publicvoidsetSqlStatement(Stringsql)
{
setTextAttribute(SQL_STATEMENT_TAG_NAME,sql);
}

publicStringgetSqlStatement()
{
returngetTextAttribute(SQL_STATEMENT_TAG_NAME);
}
privatevoidinitializeParameters()
{
ElementeDBRequest=null;
//notverynicebutthisshouldneverfail

try
{
setRequestType(SERVICE_NAME);
eDBRequest=createElementNode(SQL_STATEMENT_TAG_NAME);
}
catch(Exceptionex)
{}

eDBRequest.appendChild(dom.createTextNode(""));

try
{
setRequest(eDBRequest);
}
catch(Exceptionex)
{
}
}


扩大框架布局
我们能够对这个框架举行扩大,从而处置任何范例的服务。要想创立一个新的服务,起首必需要界说XML哀求和呼应的语法。然后,创立ServiceRequest和ServiceResponse的一个子类,它们将匡助处置服务独有的数据。最初,创立Http-ServiceHandler的一个新子类,它将处置哀求并天生得当的呼应。全部历程就是如许。

固然这个框架包括了一些功效,可是假如不增添一些更多功效的话,它在实践使用情形下还不是很有用。我无意识地省略了这些功效,以使框架布局坚持复杂,并将注重力会合到了最主要的细节上。为了完全起见,如今我们来扼要剖析这个框架布局的一些范围性和应当怎样往克制这些范围性。

起首,这个框架布局不克不及限定对服务的会见。这就意味着晓得怎样会见这个服务的每一个人都可以举行会见。在你同意对服务的会见之前,哀求某种证实能够办理这个成绩。你能够用这统一个框架来创立一个证实服务,如许就可以确认用户并天生一个独一的ID,当用户会见任何别的服务时,城市被请求这个ID。体系会将这个ID存储在某些范例的会见列表中,而且请求在一个无限工夫内,每一个哀求都必需经由过程一个无效ID才干会见服务。

别的,每次用户会见服务时,服务都要创立一个与数据库的毗连。将服务与一个毗连pooling框架组合起来能够办理这个成绩,如许就将给哀求分派一个现有毗连,而不是每次都创立新毗连。

最初一个范围是缺少session的办理。因为我们是经由过程一个socket间接会见servlet,因而不克不及利用出格有效的HttpSession工具。因为在Web服务器与扫瞄器互相感化的过程当中,在客户盘算机上没有天生sessioncookie,因而不克不及办理主动session。为了克制这个范围,我们能够实行我们本人的session办理。一个session能够是一个与独一ID相干联的工具,它能够存储别的工具。比方,你能够有一个高低文hash旌旗灯号表格,在个中存储session工具,利用独一的ID作为关头字。这个session工具还能够包括一个hash旌旗灯号表格,它存储了你想在session中保持利用的每一个工具。

这个框架使用HTTP地道手艺,同意一个桌面使用程序会见防火墙前面的服务,对其举行扩大后还供应对别的范例服务的浅易会见。

问题是他们究竟是喜欢他们是使用软件时,速度快还是速度慢好.(当然在3秒以内).无论是他们输入资料时,查找资料时,分析资料时.
再现理想 该用户已被删除
沙发
发表于 2015-1-19 12:29:40 | 只看该作者
用户端的浏览器不需要提供任何别的支持,这样大提高了用户与服务器之间的交互的速度。
透明 该用户已被删除
板凳
发表于 2015-1-28 06:02:01 | 只看该作者
跟学别的语言一样,先掌握变量,流程控制语句(就是ifwhileselect)等,函数/过程,数组
谁可相欹 该用户已被删除
地板
发表于 2015-2-5 15:16:27 | 只看该作者
最近在学asp,不要问我为什么不直接学.net,因为公司网站是asp做的所以有这个需要,卖了本书asp入门到精通,对里面的六大内置对象老是记不住,还有很多属性和方法看的头晕。
若相依 该用户已被删除
5#
发表于 2015-2-12 13:13:57 | 只看该作者
不是很难但是英文要有一点基础网上的教程很少有系统的详细的去买书吧,另不用专门学习vb关于vbscript脚本在asp教材都有介绍
山那边是海 该用户已被删除
6#
发表于 2015-3-3 03:44:49 | 只看该作者
不是很难但是英文要有一点基础网上的教程很少有系统的详细的去买书吧,另不用专门学习vb关于vbscript脚本在asp教材都有介绍
飘飘悠悠 该用户已被删除
7#
发表于 2015-3-11 09:32:00 | 只看该作者
那么,ASP.Net有哪些改进呢?
兰色精灵 该用户已被删除
8#
发表于 2015-3-18 03:25:31 | 只看该作者
不能只是将它停留在纸上谈兵的程度上。
9#
发表于 2015-3-25 10:48:02 | 只看该作者
完全不知道到底自己学的是什么。最后,除了教程里面说的几个例子,还是什么都不会。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|仓酷云 鄂ICP备14007578号-2

GMT+8, 2024-12-23 20:59

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表