WebSphere Adapter和WebSphere Process Server为SAP构建RESTful集成,第1 部分

Shan Yu, 软件工程师, IBM
 
简介: Representational State Transfer (REST) 是用于设计分布式 Web 应用程序的主流架构风格。本系列介绍如何使用 WebSphere® Adapter、WebSphere Integration Developer 和 WebSphere Process Server 构建 RESTful Web 服务,以及如何更方便地对 SAP 使用端到端业务集成解决方案。第 1 部分介绍为 SAP 的 BAPI 和 ALE 接口构建 RESTful 出站服务的两种方法。这些方法有助于开发新的业务集成解决方案,以及把现有的传统服务资产转换为 RESTful 风格。
 

简介

本文提供:

  • 对 RESTful Web 服务、WebSphere Process Server、WebSphere Integration Developer 和 WebSphere Adapter for SAP® Software 的简要概述,主要关注出站概念。
  • External Service Discovery (ESD) for SAP 的一些关键步骤。
  • 使用 WebSphere Integration Developer 为 SAP 的 Business Application Programming Interface (BAPI) 和 Application Link Enabling (ALE) 接口构建 RESTful Web 服务的两种方法。第一种方法提供轻量的客户机调用风格,而第二种方法让服务实现非常简单。

示例将使用 WebSphere Adapter for SAP V7、WebSphere Integration Developer V7 和 WebSphere Process Server V7。第一种方法和第二种方法也适用于上述产品的 Version 6.2。

 

RESTful Web 服务

Representational State Transfer (REST) 是一种用于设计分布式 Web 应用程序的架构风格。它使用 URI 代表各个资源,使用标准的 HTTP 方法(GET、POST、PUT 和 DELETE)访问资源。通信是无状态的,这意味着服务器不保留客户机通信的状态,仅仅处理当前请求。

REST 可以提高可伸缩性和简化架构。具体地说,无状态原则保证分布式服务器可以平衡请求处理负载,而客户机不会注意到差异。URI 支持一种通用且有效的命名方法。标准的 HTTP 方法可以大大简化和统一接口的设计。

符合 REST 原则的 Web 服务称为 RESTful Web 服务。目前,使用这种轻量且灵活的方法交付业务应用程序是标准方法,Yahoo®、Google®、Twitter® 等都提供 RESTful Web 服务。

 

WebSphere Process Server 和 WebSphere Integration Developer

WebSphere Process Server(后面称为 Process Server)是一种业务过程集成服务器和高性能的业务引擎。它支持在面向服务架构 (SOA) 环境中部署基于标准的业务集成应用程序。Process Server 提供丰富的集成功能,可以把各种业务服务和资产组合成优化的业务过程,见图 1。


图 1. WebSphere Process Server 概况
WebSphere Process Server 概况

WebSphere Integration Developer(后面称为 Integration Developer)是一种基于 Eclipse 的工具,用于为 WebSphere Process Server 和 WebSphere Enterprise Service Bus (ESB) 构建基于 SOA 的业务过程管理 (BPM) 和集成解决方案。它提供丰富的特性,可以简化集成开发,可以把现有的 IT 资产转换为服务组件,从而加快实现 SOA 的过程。Integration Developer 提供易用的开发环境和内置工具,可以构造跨不同企业信息系统 (EIS) 的过程和集成解决方案。

 

WebSphere Adapter for SAP Software:出站

WebSphere Adapter for SAP Software(后面称为 SAP Adapter)让应用程序能够与 SAP 服务器(SAP Web Application Server 和 SAP R/3 系统)交互并执行业务功能,而不需要编写特殊的代码。

通过使用 SAP Adapter,应用程序可以向 SAP 服务器发送请求以调用特定的函数(出站),或者从 SAP 服务器接收事件(入站)。SAP Adapter 支持多个接口以满足各种集成需求,还提供连接管理、事务处理、高可用性等高级功能。

SAP Adapter 是 Integration Developer 的组成部分,用于为 SAP 构建集成解决方案。基于 GUI 的向导 External Service Discovery (ESD) 帮助发现 SAP 中的业务服务和元数据。ESD 完成之后,解决方案所需的服务定义和工件就生成和准备好了。在此基础上,可以使用 Integration Developer 提供的先进技术和特性开发解决方案,并公开为各种类型的服务。然后,把解决方案和服务部署到 Process Server 或 ESB 上并运行。

图 2 显示在一个集成解决方案的上下文中 SAP Adapter、Process Server 和 SAP 服务器的拓扑。在这里,SAP Java™ Connector (JCo) 是用于在 SAP Adapter 和 SAP 服务器之间进行通信的中间件组件。


图 2. 使用 SAP Adapter 和 Process Server 的集成解决方案
使用 SAP Adapter 和 Process Server 的集成解决方案

对于出站,SAP Adapter 提供了多个接口,用于调用 BAPI/RFC 函数模块、提交 IDoc、查询表、调用 SAP 中的 ABAP 处理器等等。支持同步和异步(包括 qRFC 和 tRFC)调用风格。图 3 给出所有出站接口的架构概况。


图 3. SAP Adapter 出站接口的架构概况
SAP Adapter 出站接口的架构概况

在所有接口中,对于大多数 SAP 应用程序最重要的两个接口是 BAPI 和 ALE。

BAPI 接口支持对 SAP 服务器中的 BAPI 或 RFC 函数模块执行同步和异步(事务性 RFC 和队列 RFC)调用,这些模块是 SAP 中的预定义模块或定制模块,用于实现特定的 ERP 功能。使用业务对象 (BO) 代表 BAPI 调用,BO 包含输入和输出参数,见图 4。


图 4. BAPI 出站
BAPI 出站

ALE 接口支持向 SAP 服务器发送不同类型的 IDoc,转发给相应的内部过程或模块。使用 BO 代表要发送的一个或多个 IDoc 包,见图 5。


图 5. ALE 出站
ALE 出站

在本文中,我们使用 BAPI(第一种方法)和 ALE(第二种方法)构建 RESTful 服务。但是,这两种方法适用于所有出站接口,而不仅限于其中几个。

 

使用 ESD 发现 SAP 出站接口

在介绍构建 RESTful Web 服务的方法之前,需要使用 Integration Developer 中的 ESD 发现 SAP 系统中的服务和元数据。在本节中,我们演示 ESD 的一些关键步骤,而不是所有步骤。关于如何使用 ESD for SAP Adapter 的信息,请参见 Samples and Quick Start scenarios

如果已经获得了 Integration Developer 生成的传统导入(出站)服务的资产,就可以跳过本节,直接学习构建 RESTful Web 服务的 两种方法

  1. 在 Integration Developer 中,打开 Business Integration 透视图,然后单击 File > New > External Service 以启动 ESD。
  2. Adapters types 列表中选择 SAP,见图 6。

    图 6. ESD - 选择 SAP Adapter
    ESD - 选择 SAP Adapter

  3. 在 ESD 期间和部署阶段,需要 SAP JCo。配置 SAP JCo 文件的路径,见图 7。

    图 7. ESD - 找到 SAP JCo 库
    ESD - 找到 SAP JCo 库

ESD for BAPI

BAPI 实质上是 SAP 系统中的一个 RFC 函数模块。调用 BAPI 出站接口实际上是对这个模块执行 RFC 调用,从而在 SAP 中执行某个函数。在这个示例中,我们要发现一个名为 BAPI_CUSTOMER_GETDETAIL 的 BAPI,它根据提供的客户号获取客户的详细信息。

  1. 配置用于发现的 SAP 系统连接信息。另外,选择 BAPI 作为 SAP interface name,见图 8。

    图 8. ESD - 指定 BAPI 的发现属性
    ESD - 指定 BAPI 的发现属性

  2. 对于 RFC 节点的筛选,在 Find objects with this pattern 框中输入 BAPI_CUSTOMER_GETDETAIL 并单击 OK。然后展开节点,选择并导入匹配的对象,见图 9。

    图 9. ESD - 筛选并导入 BAPI
    ESD - 筛选并导入 BAPI

  3. 指定复合属性,见图 10。输入 CUSTOMER 作为 Business object name。添加 Retrieve 作为 Service operation,它映射到 BAPI_CUSTOMER_GETDETAIL

    图 10. ESD - 指定 BAPI 的复合属性
    ESD - 指定 BAPI 的复合属性

  4. 然后,根据部署和运行时环境的设置,指定部署、安全、连接等的属性,见图 11。

    图 11. ESD - 指定服务生成和部署属性
    ESD - 指定服务生成和部署属性

  5. 在 Location Properties 对话框中,单击 ModuleNew,提供名称 SAP_BAPI_OUTBOUND。在 Name 框中输入 SAPBAPIOutboundInterface(见图 12),然后单击 Finish

    图 12. ESD – 指定 BAPI 的位置属性
    ESD – 指定 BAPI 的位置属性

  6. ESD 完成之后,会在 Assembly Diagram 中创建一个带有该接口的出站服务。还可以在 Properties 视图中找到方法名 retrieveSapCUSTOMERWrapper,见图 13。后面将在函数选择器中使用这个名称。

    图 13. BAPI 出站接口
    BAPI 出站接口

ESD for ALE

对于 ALE 出站接口,为了让示例简单明了,我们使用一个简单的 IDoc ALEREQ01。这个 IDoc 用于传输材料、客户和厂商的基本数据。

  1. ALE 的 ESD 过程与 BAPI 相似。在 Discovery Properties 窗口中,选择 ALE 作为 SAP interface name,见图 14。

    图 14. ESD - 指定 ALE 的发现属性
    ESD - 指定 ALE 的发现属性

  2. 打开 Discover IDoc From System 节点的筛选,在 Find objects with this pattern 框中输入 ALEREQ01 并单击 OK。然后展开节点,选择并导入匹配的对象,见图 15。

    图 15. ESD - 筛选并导入 IDoc
    ESD - 筛选并导入 IDoc

  3. 在 Location Properties 对话框中,在 Module 框中输入 SAP_ALE_OUTBOUND_ALEREQ01,在 Name 框中输入 SAPALEOutboundInterface,见图 16。

    图 16. ESD - 指定 ALE 的位置属性
    ESD - 指定 ALE 的位置属性

  4. ESD 完成之后,会在 Assembly Diagram 中创建带有该接口的 ALE 出站服务。还可以在 Properties 视图中找到方法名 executeSapAlereq01,见图 17。后面将在函数选择器中使用这个名称。

    图 17. ALE 出站接口
    ALE 出站接口

 

第一种方法:为 SAP 出站接口构建 RESTful 服务

如果服务只需要几个或不需要输入参数,或者客户机或用户不应该提供复杂的输入(比如 XML 格式),就适合使用第一种方法。与第二种方法相比,这种方法在实现期间需要的编程量比较多,但是可以让客户机调用更简单、更容易使用。

第一种方法的示例是:用户通过以下 URL 向 RESTful Web 服务发出 HTTP GET 请求,从而通过 BAPI 出站接口获取客户的详细信息:

http://://CUSTOMER/

为了实现这个 RESTful 服务,要实现一个函数选择器类,它根据 HTTP 方法的类型选择正确的服务函数并返回函数名。然后,添加一个数据绑定类,以便把来自 URL 的原生数据解析为业务对象。这个业务对象将作为 BAPI_CUSTOMER_GETDETAIL 的输入。最后,为出站接口添加导出,为导出生成 HTTP 绑定,为绑定配置上面的类。

Web 服务模块将部署在 Process Server 上,从一个远程 HTTP 客户机测试它。

添加函数选择器类

  1. 打开 Java EE 透视图,右键单击模块项目 SAP_BAPI_OUTBOUND,选择 New > Class,在 Package 框中输入 com.ibm.rest,在 Name 框中输入 RESTFunctionSelector。在 Superclass 框中输入 HTTPFunctionSelector,单击 Browse。在 Superclass Selection 对话框中,选择惟一的匹配项(图 19),单击 OK,然后单击 Finish(图 18)。

    图 18. 创建函数选择器类
    创建函数选择器类



    图 19. 选择 HTTPFunctionSelector 作为超类
    选择 HTTPFuncti.or 作为超类

  2. 在生成的 RESTFunctionSelector 类中,修改 generateEISFunctionName 方法,让它为 HTTP GET 返回 SAPBAPIOutboundInterface 的方法名,见清单 1。在这里,还可以添加其他函数名以支持 HTTP 的 POST、PUT 和 DELETE 方法。

    清单 1. RESTFunctionSelector 类
    						
    public class RESTFunctionSelector extends HTTPFunctionSelector {
    
     @Override
      public String generateEISFunctionName(HTTPControl arg0, HTTPHeaders arg1,
        HTTPInputStream arg2) throws SelectorException {
      if (arg0.getMethod().equals("GET")){
    	return "retrieveSapCUSTOMERWrapper";
      } else {
    	return null;
      }
     }
    }

添加数据绑定类

  1. 选择 New > Class 添加另一个类,在 Package 框中输入 com.ibm.rest,在 Name 框中输入 RESTDataBinding,见图 20。
  2. Superclass 框中输入 HTTPStreamDataBindingBytes(见图 21),然后单击 Browse。在 Superclass Selection 对话框中,选择惟一的匹配项,单击 OK,然后单击 Finish

    图 20. 添加数据绑定类
    添加数据绑定类



    图 21. 选择 HTTPStreamDataBindingBytes 作为超类
    选择 HTTPStreamDataBindingBytes 作为超类

  3. 修改生成的 RESTDataBinding 类,见清单 2。在这里,通过 URL 的最后一个 “/” 后面的参数获取客户号。然后,为 BAPI 创建新的输入业务对象,在输入业务对象的属性中设置客户号。

    清单 2. RESTDataBinding 类
    						
    package com.ibm.rest;
    
    import java.io.IOException;
    import com.ibm.websphere.http.data.bindings.HTTPStreamDataBindingBytes;
    import com.ibm.websphere.http.data.streams.HTTPInputStream;
    import com.ibm.websphere.sca.sdo.DataFactory;
    import commonj.connector.runtime.DataBindingException;
    import commonj.sdo.DataObject;
    
    public class RESTDataBinding extends HTTPStreamDataBindingBytes {
     DataObject dataobject = null;
     String nativeData = null;
    
     public void convertFromNativeData(HTTPInputStream httpinputstream)
      throws DataBindingException, IOException {
    	setDataObject(parseNativeData(parseRestURL(getControlParameters().getURL())));
      }
    
    	/*
    	 * Create a data object of a specific type, 
    	 * then set the properties of the data object with values parsed from input 
    	 */
    	public DataObject parseNativeData(byte arg[]) {
    		
    		// Note: Customize the namespace and name according to your generated
     Business Object schemas (xsd)
    		dataobject = 
    DataFactory.INSTANCE.create("http://www.ibm.com/xmlns/prod/websphere/j2ca/sap/
    sapcustomerwrapper", "SapCUSTOMERWrapper");
    		dataobject.createDataObject("SapBapiCustomerGetdetail");
    		dataobject.getDataObject("SapBapiCustomerGetdetail").setString
    ("CustomerToBeRequired", new String(arg));
    
    		return dataobject;
    	}
    
    	public DataObject getDataObject() {
    		return dataobject;
    	}
    
    	private
     byte[] parseRestURL(String URL) {
    		return URL.substring(URL.lastIndexOf('/') + 1).getBytes();
    	}
    }

生成并配置 HTTP 绑定

  1. 打开 Assembly Diagram,从左边的 Palette 面板中把 Export 拖动到画布上,见图 22。把它改名为 BAPIRestExport,然后把它连接到 SAPBAPIOutboundInterface。在弹出的 Add Wire 对话框中单击 OK,单击 Save

    图 22. 添加 Export 并连接到 BAPI 出站服务
    添加 Export 并连接到 BAPI 出站服务

  2. 右键单击 BAPIRestExport 并选择 Generate Binding > HTTP Binding。在 Configure HTTP Export Service 对话框中,在 Context path 中输入 /CUSTOMER,见图 23。

    图 23. 配置 HTTP 绑定
    配置 HTTP 绑定

  3. 在弹出的 Data Transformation Configuration 对话框中,单击 Select for Default data format,单击 Select your custom data format transformation from the workspace 的单选按钮,见图 24。然后单击 Select,输入 REST 并选择匹配的 RESTDataBinding 类,见图 25。单击 OKFinish

    图 24. 配置数据转换
    配置数据转换



    图 25. 选择 RESTDataBinding
    选择 RESTDataBinding

  4. 与数据转换相似,单击 Select for Function selector ,见图 23。然后,选择 RESTFunctionSelector 作为函数选择器类,见图 26。单击 Finish

    图 26. 选择函数选择器
    选择函数选择器

  5. 生成 HTTP 绑定之后,会在 BAPIRestExport 的 Properties 视图中看到以上配置,见图 27。

    图 27. Properties 视图中的 HTTP 绑定
    Properties 视图中的 HTTP 绑定

  6. 现在进入 Method Bindings,在 Context path 中输入 /*,见图 28。

    图 28. 配置方法绑定 - 一般设置
    配置方法绑定 - 一般设置

  7. 进入 Method BindingsData Serialization 选项卡,选择 RESTDataBinding 作为 Input data format(过程与图 24 相似)。然后选择 UTF8XMLDataHandler 作为 Output data format,见图 29 和图 30。保存所有修改。

    图 29. 配置方法绑定 - 数据序列化
    配置方法绑定 - 数据序列化



    图 30. 选择 UTF8XMLDataHandler
    选择 UTF8XMLDataHandler

部署和测试 RESTful BAPI 接口

现在,要把 Web 服务模块部署到 Process Server 上。

  1. 打开 Server 视图,右键单击 Process Server 实例,选择 Add and Remove Projects 以将模块项目添加到 Process Server 上。
  2. 在发出请求之前,从 Process Server 的 Admin Console 获得这个模块的上下文根:Applications > Application Types > WebSphere enterprise application > SAP_BAPI_OUTBOUNDApp > Context Root for Web Modules。我们的 Web 模块使用 SAP_BAPI_OUTBOUNDWeb 作为上下文根,见图 31。

    图 31. 从 Admin Console 获得 Web 模块的上下文根
    从 Admin Console 获得 Web 模块的上下文根

  3. Poster 是 Firefox® 的附加组件,用于通过各种 HTTP 方法与 Web 服务和 Web 资源交互。我们使用它对以下 URL 发出 GET 请求以测试 RESTful Web 服务(“0000000001” 是要查询的客户号),见图 32。
    http://9.186.115.135:9080/SAP_BAPI_OUTBOUNDWeb/CUSTOMER/0000000001



    图 32. 通过 Poster 测试 BAPI RESTful Web 服务
    通过 Poster 测试 BAPI RESTful Web 服务

  4. 发送请求之后,在 Process Server 的 HTTP 响应中以 XML 格式返回客户详细信息,见图 33。

    图 33. BAPI RESTful Web 服务的响应
    BAPI RESTful Web 服务的响应

 

第二种方法:为 SAP 出站接口构建 RESTful 服务

第二种方法更灵活,适用于需要 XML 格式的输入数据的大多数 SAP 出站请求。它的实现也比较简单。

第二种方法的示例是:用户通过以下 URL 向 RESTful Web 服务发出 POST 请求,从而通过 ALE 出站接口在 SAP 系统中创建 ALEREQ01 IDoc。通过 HTTP POST 请求体以 XML 格式提供 IDoc 的内容。

http://://ALEREQ01

为了实现这个 RESTful 服务,要实现一个函数选择器类,它根据 HTTP 方法返回目标函数名,这与第一种方法相同。对于数据转换,使用内置的 UTF8XMLDataHandler 把 HTTP 请求体中的 XML 数据解析为业务对象作为输入,还把业务对象转换为 XML 数据作为响应。然后,演示如何添加导出、生成 HTTP 绑定和配置绑定。

添加函数选择器类

  1. SAP_ALE_OUTBOUND 项目中添加一个新类,在 Package 框中输入 com.ibm.rest,在 Name 框中输入 RESTFunctionSelector,选择 HTTPFunctionSelector 作为 Superclass,见图 34。

    图 34. 创建函数选择器类
    创建函数选择器类

  2. 然后修改 generateEISFunctionName,见清单 3。

    清单 3. RESTFunctionSelector 类
    						
    public class RESTFunctionSelector extends HTTPFunctionSelector {
    
    	@Override
    	public String generateEISFunctionName(HTTPControl arg0, HTTPHeaders arg1,
     HTTPInputStream arg2) throws SelectorException {
    	if (arg0.getMethod().equals("POST")){
    		return "executeSapAlereq01";
    	} else {
    		return null;
    	}
     }
    }

生成并配置 HTTP 绑定

  1. 打开 Assembly Diagram,从左边的 Palette 面板中把 Export 拖动到画布上。把它改名为 ALERestExport,然后把它连接到 SAPALEOutboundInterface(图 35)。在弹出的 Add Wire 对话框中单击 OK,单击 Save

    图 35. 添加 Export 并连接到 ALE 出站服务
    添加 Export 并连接到 ALE 出站服务

  2. 右键单击 ALERestExport 并选择 Generate Binding > HTTP Binding。在 Configure HTTP Export Service 对话框中,在 Context path 中输入 /ALEREQ01,见图 36。对于 Default data format,选择 UTF8XMLDataHandler(默认)。对于 Function selector,选择 RESTFunctionSelector。单击 OK

    图 36. 配置 HTTP 绑定
    配置 HTTP 绑定

  3. 生成 HTTP 绑定之后,会在 ALERestExport 的 Properties 视图中看到以上配置,见图 37。

    图 37. Properties 视图中的 HTTP 绑定
    Properties 视图中的 HTTP 绑定

  4. 现在进入 Method Bindings > Generic,在 Context path 中输入 /*,见图 38。

    图 38. 配置方法绑定 - 一般设置
    配置方法绑定 - 一般设置

  5. 进入 Method BindingsData Serialization 选项卡,选择 UTF8XMLDataHandler 作为 Input data formatOutput data format,见图 39。

    图 39. 配置方法绑定 - 数据序列化
    配置方法绑定 - 数据序列化

  6. 最后,进入 HTTP Method Settings 选项卡并单击 Add。在弹出的对话框中,选择 POST 并使用默认值,单击 OK。结果见图 40。保存所有修改。

    图 40. 配置方法绑定 - HTTP 方法设置
    配置方法绑定 - HTTP 方法设置

部署和测试 RESTful ALE 接口

现在,要把 Web 服务模块部署到 Process Server 上。

  1. 打开 Server 视图,右键单击 Process Server 实例,选择 Add and Remove Projects 以将模块项目添加到 Process Server 上。
  2. 在发出请求之前,从 Process Server 的 Admin Console 获得这个模块的上下文根:Applications > Application Types > WebSphere enterprise application > SAP_ALE_OUTBOUNDApp > Context Root for Web Modules。我们的 Web 模块使用 SAP_ALE_OUTBOUNDWeb 作为上下文根,见图 41。

    图 41. 从 Admin Console 获得 Web 模块的上下文根
    从 Admin Console 获得 Web 模块的上下文根

  3. 使用 Poster 对以下 URL 发出 GET 请求以测试 RESTful Web 服务:
    http://9.186.115.135:9080/SAP_ALE_OUTBOUNDWeb/ALEREQ01

  4. 另外,在 Content to Send 中提供输入业务对象的 XML 内容,见图 42 和清单 4。

    图 42. 通过 Poster 测试 ALE RESTful Web 服务
    通过 Poster 测试 ALE RESTful Web 服务



    清单 4. IDoc ALEREQ01 的示例业务对象
    						
    <?xml version="1.0" encoding="UTF-8"?>SAP**1LSALEREQ01SYUSERVEREDI_DC40200ALEREQSAPCLNT200SYUPORT001LSALEREQALEREQ50EEQ0100

  5. 发送 IDoc 之后,返回输出业务对象的 XML 内容,其中包含这个 ALE 异步请求的事务 ID,见图 43。

    图 43. ALE RESTful Web 服务的响应
    ALE RESTful Web 服务的响应

 

结束语

本文介绍了如何使用 WebSphere Adapter for SAP、WebSphere Integration Developer 和 WebSphere Process Server 为 SAP 出站接口构建 RESTful Web 服务。使用 ESD for SAP Adapter 发现 SAP 中的出站服务和元数据。本文介绍了两种方法,第一种方法实现函数选择器和数据绑定并配置 HTTP 绑定,从而为 BAPI 接口构建 RESTful 服务。第二种方法实现函数选择器并为 HTTP 绑定配置预定义的数据处理器,从而为 ALE 接口构建 RESTful 服务。这些方法不但有助于更方便地为业务集成构建全新的 RESTful Web 服务,还有助于以 RESTful 方式利用现有的服务资产。

 

原文链接:http://www.ibm.com/developerworks/cn/websphere/library/techarticles/1004_yu/1004_yu.html

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/14789789/viewspace-669483/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/14789789/viewspace-669483/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值