Web Service学习笔记

转载于: http://blog.csdn.net/bayougeng/archive/2009/07/27/4384260.aspx

 

 

本文是在公司做Web Service技术研究时候的文档。部分资料来源于网络,部分是我自己的体会。贴出来给Web Service的初学者,希望能加快你们学习的步伐。

第一部分:主要介绍Web Service以及相关的协议、术语的概念以及Web Service的特点。

Web Service:

    是一种革命性的分布式计算技术。它使用基于XML的消息处理作为基本的数据通讯方式。消除使用不同组件模型、操作系统和编程语言的系统之间存在的差异,使异类系统能够作为计算网络的一部分协同运行。开发人员可以使用像过去创建分布式应用程序时使用组件的方式,创建由各种来源的Web服务组合在一起的应用程序。由于Web服务是建立在一些通用协议的基础上,如HTTP,SOAP,XML,WSDL,UDDI等,这些协议在涉及到操作系统、对象模型和编程语言的选择时,没有任何倾向。因此Web服务将会有很强的生命力。

SOAP:

    是“Simple Object Access Protocol”的缩写,SOAP是消息传递的协议,它规定了Web Services之间是怎样传递信息的。简单的说,SOAP规定了:
  1. 传递信息的格式为XML。这就使Web Services能够在任何平台上,用任何语言进行实现。
  2. 远程对象方法调用的格式。规定了怎样表示被调用对象以及调用的方法名称和参数类型等。
  3. 参数类型和XML格式之间的映射。这是因为,被调用的方法有时候需要传递一个复杂的参数,例如,一个Person对象。怎样用XML来表示一个对象参数,也是SOAP所定义的范围。

WSDL:

    是“Web Services Description Language”的缩写。WSDL是Web Services的定义语言。当实现了某种服务的时候(如:股票查询服务),为了让别的程序调用,必须告诉大家服务接口。例如:服务名称,服务所在的机器名称,监听端口号,传递参数的类型,个数和顺序,返回结果的类型等等。这样别的应用程序才能调用该服务。WSDL协议就是规定了有关Web Services描述的标准。


UDDI:

    是“Universal Description, Discovery,and Integration”的缩写。简单说,UDDI用于集中存放和查找WSDL描述文件,起着目录服务器的作用。


XML:

    (eXtensible Markup Language,可扩展标记语言)是Internet上数据表示和数据交换的新标准。它是ISO(International Organization for Standardization,国际标准化组织)的SGML(Standard for General Markup Language,通用标记语言标准)的一个简化子集。XML关注信息本身,是Web上表示结构化信息的一种标准文本格式。与传统的注重页面信息显示的 HTML(Hypertext Markup Language,超文本链接标示语言)相比,关注于内容的XML具有以下诸多优点:良好的可扩展性,语言简单有效,可自行定义标记;内容与形式的分离,主要刻画数据内容,不考虑显示效果;有严格的语法要求,便于分析统一和与数据库信息转换;便于传输,为纯文本形式,可通过Http协议直接传输,可跨越防火墙;等等。


DTD:

    (Document Type Definition,文档类型定义)DTD 是一套关于标记符的语法规则。它是XML1.0版规格得一部分,是XML文件的验证机制,属于XML文件组成的一部分。DTD 是一种保证XML文档格式正确的有效方法,可以通过比较XML文档和DTD文件来看文档是否符合规范,元素和标签使用是否正确。DTD文档包含:元素的定义规则,元素间关系的定义规则,元素可使用的属性,可使用的实体或符号规则。XML文件提供应用程序一个数据交换的格式,DTD正是让XML文件能够成为数据交换的标准,因为不同的公司只需定义好标准的DTD,各公司都能够依照DTD建立XML文件,并且进行验证,如此就可以轻易的建立标准和交换数据,这样满足了网络共享和数据交互。DTD文件是一个ASCII的文本文件,后缀名为.dtd。


WS-I:

    WS-I全称为:网络服务标准组织。WS-I Basic Profile是为了开发可相互连接的Web服务而推出的指南,介绍了如何配合使用SOAP、WSDL、UDDI、XML、XML Schema等Web服务的核心标准。


Axis:

    Axis(Apache extensible Interaction system)是Apache项目组织的一个开源项目。前身是Apache SOAP。Axis总体上是一个SOAP引擎,但又不仅仅是个引擎,它还:
        1)是一个简单的独立的服务器
        2)是一个可插入到servlet引擎(如Tomcat)中的服务
        3)可扩展的支持WSDL
        4)能根据WSDL产生JAVA文件/类
        5)包括一些例子程序6)包括一个可以监控TCP/IP包的工具
    Axis支持三种web service的部署和开发,分别为:
        1、Dynamic Invocation Interface ( DII)
        2、Dynamic Proxy方式
        3、Stubs方式
    对于前两种Web Service的发布基本一样,客户端的访问也很类似,第一种发布就是直接将.java后缀改为.jws,并将生成的.class文件拷贝到WEB-INF/jwsclasses下面。
第三种是目前比较流行的方式。也是Force.com Web Service采用的方式。stub意思是树桩,意味着服务端和客户端都是通过桩的形式来完成访问的,即在服务端将java转换成wsdl,在客户端将wsdl装换成java,这样就实现了良好的桩的分离。


--------------------------------------------------------------------------------

第二部分:主要介绍使用Axis开发Web Service使用的工具、工具版本以及配置步骤。


工具/开发包              版本

JDK                        1.6

eclipse                   3.2.2

Axis                       1.4

Tomcat                  5.5

tomcatPluginV31    -

1.安装jdk1.6。

2.释放eclipse的压缩包。我释放的路径是:D:/Program Files。

3.释放Tomcat压缩包。我释放的路径是:D:/Server。

4.释放Axis压缩包。我的释放路径是:D:/Server。

5.安装eclipse下开发tomcat的plugin,这里不细述。


--------------------------------------------------------------------------------

第三部分:主要介绍如何构造简单的Web Service服务。

1.通过最基本的DII方式式构建Web Service。

  1.1.在eclipse中建立新的tomcat工程。名字:AxisTest

  1.2.将axis-1_4/webapps/axis中几个必须的文件拷贝到你的AxisTest工程文件下。其一是WEB-INF/lib下的所有文件,其二是WEB-INF下面的web.xml文件。

  1.3.将三个jar导入工程的WEB-INF/lib下。分别是:tools.jar,activation.jar,mail.jar(这三个是常用的jar,应该很熟悉吧?)。

  1.4.在源文件目录下,建立文件MyService1.java。内容如下:

view plaincopy to clipboardprint?
public class MyService1 {  
   
 public String showWelcomeMessage(String userName){  
  return "Hello " + userName + ",you are welcome to TSR.";  
 }  

public class MyService1 {
 
 public String showWelcomeMessage(String userName){
  return "Hello " + userName + ",you are welcome to TSR.";
 }
}

  1.5.将这MyService1.java移动到AxisTest根目录下。并修改扩展名为.jws。

  1.6.用浏览器访问下面的地址:http://localhost:8080/AxisTest/MyService1.jws,如果配置正确,可以得到下面的画面:

 

点击这个link,服务器端会编译MyService1.jws文件,在WEB-INF/jwsClasses目录中生成.class文件。

MyService1这个Web Service就成功发布了。

结果页面看到的就是这个Web Service的WSDL文件。如下图:

 

  1.7.接下来我们写一个java程序来调用这个Web Service。代码如下:

view plaincopy to clipboardprint?
package cn.com.ctsr.axis.runable;  
 
import java.net.MalformedURLException;  
import java.rmi.RemoteException;  
 
import javax.xml.rpc.ParameterMode;  
import javax.xml.rpc.ServiceException;  
 
import org.apache.axis.client.Call;  
import org.apache.axis.client.Service;  
import org.apache.axis.encoding.XMLType;  
 
public class TestService {  
 
 /** 
  * @param args 
  */ 
 public static void main(String[] args) throws ServiceException,  
   MalformedURLException, RemoteException {  
  // TODO Auto-generated method stub  
  String endpoint = "
http://localhost:8080/AxisTest/MyService1.jws";  
  String name = "YangBo";  
  Service service = new Service();  
  Call call = (Call) service.createCall();  
 
  call.setTargetEndpointAddress(new java.net.URL(endpoint));  
  call.addParameter("userName", XMLType.XSD_STRING, ParameterMode.IN);  
  call.setOperationName("showWelcomeMessage");  
  call.setReturnType(XMLType.XSD_STRING);  
  String ret = (String) call.invoke(new Object[] { name });  
  System.out.println("The result:" + ret);  
 }  
 

package cn.com.ctsr.axis.runable;

import java.net.MalformedURLException;
import java.rmi.RemoteException;

import javax.xml.rpc.ParameterMode;
import javax.xml.rpc.ServiceException;

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.encoding.XMLType;

public class TestService {

 /**
  * @param args
  */
 public static void main(String[] args) throws ServiceException,
   MalformedURLException, RemoteException {
  // TODO Auto-generated method stub
  String endpoint = "
http://localhost:8080/AxisTest/MyService1.jws";
  String name = "YangBo";
  Service service = new Service();
  Call call = (Call) service.createCall();

  call.setTargetEndpointAddress(new java.net.URL(endpoint));
  call.addParameter("userName", XMLType.XSD_STRING, ParameterMode.IN);
  call.setOperationName("showWelcomeMessage");
  call.setReturnType(XMLType.XSD_STRING);
  String ret = (String) call.invoke(new Object[] { name });
  System.out.println("The result:" + ret);
 }

}

运行程序得到如下的结果:.

The result:Hello YangBo,you are welcome to TSR.

注意,这种方式暂时用不上WSDL。

到这里,一个最简单的Web Service就构造成功了。

2.下面介绍另外一种方式,也是目前最流行的方式:Stubs方式。

  2.1.建立服务器端运行的Web Service程序。我的服务程序如下:

view plaincopy to clipboardprint?
package cn.com.ctsr.axistest.server;  
 
import jp.co.sei.is.lib21.SeiCalc;  
 
public class MyService2 {  
 
 public String calculate(String expression){  
   
  return SeiCalc.eval(expression);  
 }  

package cn.com.ctsr.axistest.server;

import jp.co.sei.is.lib21.SeiCalc;

public class MyService2 {

 public String calculate(String expression){
 
  return SeiCalc.eval(expression);
 }
}
 

  *这里使用了的jp.co.sei.is.lib21.SeiCalc#eval请自行找方法替代。因为大家可能没有这个开发包。这个方法是做一个计算。参数是一个计算式,返回这个计算式的值。比如,参数:2*3,返回值:5。

  2.2.在工程目录下,建立文件夹:java2wsdl。并做成新的文件:build.xml。这个文件用来根据Web Service类生成wsdl文件。内容如下:

   view plaincopy to clipboardprint?
<?xml version="1.0"?> 
 
<project name="Generate WSDL from JavaBeans as Web Services" default="j2w-all" basedir="."> 
 <property name="build.dir" value="../WEB-INF/classes"/> 
 <path id="classpath.id"> 
  <fileset dir="../WEB-INF/lib"> 
   <include name="*.jar"/> 
  </fileset>     
  <pathelement location="${build.dir}"/> 
 </path> 
 <taskdef name="axis-java2wsdl" classname="org.apache.axis.tools.ant.wsdl.Java2WsdlAntTask" 
     loaderref="axis" > 
  <classpath refid="classpath.id"/> 
  </taskdef> 
 <target name="j2w-all"> 
  <antcall target="j2w-JavaBeanWS"/>         
 </target> 
 <target name="j2w-JavaBeanWS"> 
  <axis-java2wsdl      
   classname="cn.com.ctsr.axistest.server.MyService2"   
   classpath="${build.dir}" 
   methods="calculate" 
   output="MyService2.wsdl" 
   location="
http://172.28.18.19:8080/AxisTest/services/MyService2
   namespace="
http://172.28.18.19:8080/AxisTest/services/MyService2
   namespaceImpl="
http://172.28.18.19:8080/AxisTest/services/MyService2">          
  </axis-java2wsdl> 
 </target> 
</project> 
<?xml version="1.0"?>

<project name="Generate WSDL from JavaBeans as Web Services" default="j2w-all" basedir=".">
 <property name="build.dir" value="../WEB-INF/classes"/>
 <path id="classpath.id">
  <fileset dir="../WEB-INF/lib">
   <include name="*.jar"/>
  </fileset>  
  <pathelement location="${build.dir}"/>
 </path>
 <taskdef name="axis-java2wsdl" classname="org.apache.axis.tools.ant.wsdl.Java2WsdlAntTask"
     loaderref="axis" >
  <classpath refid="classpath.id"/>
  </taskdef>
 <target name="j2w-all">
  <antcall target="j2w-JavaBeanWS"/>      
 </target>
 <target name="j2w-JavaBeanWS">
  <axis-java2wsdl   
   classname="cn.com.ctsr.axistest.server.MyService2"
   classpath="${build.dir}"
   methods="calculate"
   output="MyService2.wsdl"
   location="
http://172.28.18.19:8080/AxisTest/services/MyService2"
   namespace="
http://172.28.18.19:8080/AxisTest/services/MyService2"
   namespaceImpl="
http://172.28.18.19:8080/AxisTest/services/MyService2">       
  </axis-java2wsdl>
 </target>
</project>

  2.3.在工程WEB-INF目录下建立新文件:server-config.wsdd。这个文件用来配置服务器所有的Web Service。内容如下:

view plaincopy to clipboardprint?
<?xml version="1.0" encoding="UTF-8"?> 
<deployment xmlns="
http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> 
 <globalConfiguration> 
  <parameter name="adminPassword" value="admin"/> 
  <parameter name="attachments.Directory" value="C:/eclipse/workspace/bookstore/WEB-INF/attachments"/> 
  <parameter name="attachments.implementation" value="org.apache.axis.attachments.AttachmentsImpl"/> 
  <parameter name="sendXsiTypes" value="true"/> 
  <parameter name="sendMultiRefs" value="true"/> 
  <parameter name="sendXMLDeclaration" value="true"/> 
  <parameter name="axis.sendMinimizedElements" value="true"/> 
  <requestFlow> 
   <handler type="java:org.apache.axis.handlers.JWSHandler"> 
    <parameter name="scope" value="session"/> 
   </handler> 
   <handler type="java:org.apache.axis.handlers.JWSHandler"> 
    <parameter name="scope" value="request"/> 
    <parameter name="extension" value=".jwr"/> 
   </handler> 
  </requestFlow> 
 </globalConfiguration> 
 <handler name="LocalResponder" type="java:org.apache.axis.transport.local.LocalResponder"/> 
 <handler name="Authenticate" type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/> 
 <handler name="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/> 
 <service name="Version" provider="java:RPC"> 
  <parameter name="allowedMethods" value="getVersion"/> 
  <parameter name="className" value="org.apache.axis.Version"/> 
 </service> 
 <service name="AdminService" provider="java:MSG"> 
  <parameter name="allowedMethods" value="AdminService"/> 
  <parameter name="enableRemoteAdmin" value="false"/> 
  <parameter name="className" value="org.apache.axis.utils.Admin"/> 
  <namespace>http://xml.apache.org/axis/wsdd/</namespace> 
 </service> 
 <service name="MyService2" provider="java:RPC"> 
  <parameter name="className" value="cn.com.ctsr.axistest.server.MyService2"/> 
  <parameter name="allowedMethods" value="*"/> 
 </service> 
 <transport name="local"> 
  <responseFlow> 
   <handler type="LocalResponder"/> 
  </responseFlow> 
 </transport> 
 <transport name="http"> 
  <requestFlow> 
   <handler type="URLMapper"/> 
   <handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/> 
  </requestFlow> 
 </transport> 
</deployment> 
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="
http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
 <globalConfiguration>
  <parameter name="adminPassword" value="admin"/>
  <parameter name="attachments.Directory" value="C:/eclipse/workspace/bookstore/WEB-INF/attachments"/>
  <parameter name="attachments.implementation" value="org.apache.axis.attachments.AttachmentsImpl"/>
  <parameter name="sendXsiTypes" value="true"/>
  <parameter name="sendMultiRefs" value="true"/>
  <parameter name="sendXMLDeclaration" value="true"/>
  <parameter name="axis.sendMinimizedElements" value="true"/>
  <requestFlow>
   <handler type="java:org.apache.axis.handlers.JWSHandler">
    <parameter name="scope" value="session"/>
   </handler>
   <handler type="java:org.apache.axis.handlers.JWSHandler">
    <parameter name="scope" value="request"/>
    <parameter name="extension" value=".jwr"/>
   </handler>
  </requestFlow>
 </globalConfiguration>
 <handler name="LocalResponder" type="java:org.apache.axis.transport.local.LocalResponder"/>
 <handler name="Authenticate" type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/>
 <handler name="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/>
 <service name="Version" provider="java:RPC">
  <parameter name="allowedMethods" value="getVersion"/>
  <parameter name="className" value="org.apache.axis.Version"/>
 </service>
 <service name="AdminService" provider="java:MSG">
  <parameter name="allowedMethods" value="AdminService"/>
  <parameter name="enableRemoteAdmin" value="false"/>
  <parameter name="className" value="org.apache.axis.utils.Admin"/>
  <namespace>http://xml.apache.org/axis/wsdd/</namespace>
 </service>
 <service name="MyService2" provider="java:RPC">
  <parameter name="className" value="cn.com.ctsr.axistest.server.MyService2"/>
  <parameter name="allowedMethods" value="*"/>
 </service>
 <transport name="local">
  <responseFlow>
   <handler type="LocalResponder"/>
  </responseFlow>
 </transport>
 <transport name="http">
  <requestFlow>
   <handler type="URLMapper"/>
   <handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/>
  </requestFlow>
 </transport>
</deployment>

  *请注意,<service name="MyService2" provider="java:RPC">就是我们自己的Web Service的配置。另外还有两个Web Service是Axis自带的。其他地方的配置请参考相关文档。

  2.4.右键点击java2wsdl/build.xml,选择run as -> Ant Build。此操作成功执行后,会在该文件夹下生成MyService2.wsdl文件。这个文件就是我们自定义的Web Service:MyService2的wsdl文件。

  2.5.启动tomcat,访问网址:http://172.28.18.19:8080/AxisTest/services。正确的结果如下图:

 

服务器端的工作到这里就完成了,下面我们在客户端做一个程序来调用这个Web Service。

  2.6.在工程根目录下,新建一个新的source folder,名称:wsdl2java。在这个目录下建立新的文件:build.xml。此文件用来从服务器端获得指定Web Service的wsdl文件,并转换成客户端使用所需要的java类。内容如下:

 view plaincopy to clipboardprint?
<?xml version="1.0" encoding="UTF-8"?> 
<project name="wsclient" default="all" basedir="."> 
<property name="axis.home" location="D:/Server/axis-1_4"/> 
<property name="options.output" location="../wsdl2java"/> 
<path id="axis.classpath"> 
 <fileset dir="../WEB-INF/lib"> 
  <include name="*.jar"/> 
 </fileset> 
</path> 
<taskdef resource="axis-tasks.properties" classpathref="axis.classpath" /> 
<target name="-WSDL2Axis"> 
 <mkdir dir="${options.output}"/> 
 <axis-wsdl2java   
  output="${options.output}"   
  debug="true" 
  url="
http://172.28.18.19:8080/AxisTest/java2wsdl/MyService2.wsdl"   
  deployscope="Request" 
  testcase="false" 
  noimports="false" 
  verbose="true"/> 
</target> 
<target name="all"> 
 <antcall target="MyService2"/>          
</target> 
<target name="MyService2"> 
 <antcall target="-WSDL2Axis"> 
  <param name="options.WSDL-URI" location="
http://172.28.18.19:8080/AxisTest/java2wsdl/MyService2.wsdl"/
 </antcall> 
</target>           
</project> 
<?xml version="1.0" encoding="UTF-8"?>
<project name="wsclient" default="all" basedir=".">
<property name="axis.home" location="D:/Server/axis-1_4"/>
<property name="options.output" location="../wsdl2java"/>
<path id="axis.classpath">
 <fileset dir="../WEB-INF/lib">
  <include name="*.jar"/>
 </fileset>
</path>
<taskdef resource="axis-tasks.properties" classpathref="axis.classpath" />
<target name="-WSDL2Axis">
 <mkdir dir="${options.output}"/>
 <axis-wsdl2java
  output="${options.output}"
  debug="true"
  url="
http://172.28.18.19:8080/AxisTest/java2wsdl/MyService2.wsdl"
  deployscope="Request"
  testcase="false"
  noimports="false"
  verbose="true"/>
</target>
<target name="all">
 <antcall target="MyService2"/>       
</target>
<target name="MyService2">
 <antcall target="-WSDL2Axis">
  <param name="options.WSDL-URI" location="
http://172.28.18.19:8080/AxisTest/java2wsdl/MyService2.wsdl"/>
 </antcall>
</target>        
</project>

  *注意url="http://172.28.18.19:8080/AxisTest/java2wsdl/MyService2.wsdl"这个部分。如果想使用本地文件目录中的wsdl文件,而不是使用web上的wsdl文件,需要这样写:

  url="file:///d:/Program Files/eclipse322/workspace/AxisTest/java2wsdl/MyService2.wsdl"

  "file"后面有三个斜线,千万别错了。

  2.7.右键点击wsdl2java/build.xml,选择run as -> Ant Build。如果配置正确,运行后会在此目录下生成一个包。包中包括4个java文件。

  2.8.新建一个java文件。用来调用刚刚Web Service。我已经写好了一个,代码如下:

view plaincopy to clipboardprint?
package cn.com.ctsr.axistest.client;  
 
import java.io.BufferedReader;  
import java.io.InputStreamReader;  
 
import jp.co.sei.is.lib21.SeiUtil;  
import _19._18._28._172.AxisTest.services.MyService2.MyService2;  
import _19._18._28._172.AxisTest.services.MyService2.MyService2ServiceLocator;  
 
public class TestService2 {  
 
 /**  
  * @param args 
  */ 
 public static void main(String[] args){  
  // TODO Auto-generated method stub  
  MyService2ServiceLocator Service= new MyService2ServiceLocator();  
  MyService2 port= null;  
  BufferedReader p_in = new BufferedReader(  
    new InputStreamReader(System.in));  
  String p_expression = null;  
  try{  
   port = Service.getMyService2();  
   while(!SeiUtil.isEmpty(p_expression = p_in.readLine())){  
    String response=port.calculate(p_expression);  
    System.out.println(p_expression + " = " + response);  
   }  
  }catch(Exception e){  
   e.printStackTrace(System.err);  
  }  
 
  System.out.print("Bye!");  
 }  
 

package cn.com.ctsr.axistest.client;

import java.io.BufferedReader;
import java.io.InputStreamReader;

import jp.co.sei.is.lib21.SeiUtil;
import _19._18._28._172.AxisTest.services.MyService2.MyService2;
import _19._18._28._172.AxisTest.services.MyService2.MyService2ServiceLocator;

public class TestService2 {

 /**
  * @param args
  */
 public static void main(String[] args){
  // TODO Auto-generated method stub
  MyService2ServiceLocator Service= new MyService2ServiceLocator();
  MyService2 port= null;
  BufferedReader p_in = new BufferedReader(
    new InputStreamReader(System.in));
  String p_expression = null;
  try{
   port = Service.getMyService2();
   while(!SeiUtil.isEmpty(p_expression = p_in.readLine())){
    String response=port.calculate(p_expression);
    System.out.println(p_expression + " = " + response);
   }
  }catch(Exception e){
   e.printStackTrace(System.err);
  }

  System.out.print("Bye!");
 }

}

  *注意_19._18._28._172.AxisTest.services.MyService2.MyService2和_19._18._28._172.AxisTest.services.MyService2.MyService2ServiceLocator就是2.7最终生成的class。

  2.9.运行2.8中做成的客户端程序,得到类似下面的运行结果:

 

Stubs方式的Web Service就完成了。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/bayougeng/archive/2009/07/27/4384260.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值