电子卡券扩展点使用教程

场景

由于有赞云电子卡券标准的生成方式不对商家暴露卡券券码信息,也不提供获取卡券信息的 API 接口,这主要是从电子卡券类商品的特殊性考虑,有赞默认卡券信息属于用户的私有财产而非商家的,但是有些商家需要实现自己拿到电子卡券信息做一些扩展功能或者与已有的三方卡券生产系统做对接,希望将生成的卡券信息同步到有赞来,那么这个时候就可以使用电子卡券扩展点来实现与三方卡券系统进行对接。

那么本文就针对创建电子卡券的这个流程进行讲解如何去使用扩展点实现这一功能。

准备工作

首先,要使用扩展点,你必须具备以下条件:

克隆项目

这里假设你已经创建了自用型容器,我们从首页进入到该容器中,点击应用概况,切换到 GIT 仓库信息,点击拉取代码到本地链接,在弹出的对话框中选择复制

将项目克隆到本地

配置 maven

克隆后先不要着急 import 项目,我们先配置下 Maven 的 setting.xml 文件,因为工程需要依赖一些特有的 JAR 包,
这里使用的 maven 版本是 apache-maven-3.6.3 maven 配置参考文档中的 maven 配置说明 https://doc.youzanyun.com/doc#/content/35700/36575

工程说明

打开 idea,导入项目并下载对应的 jar 包,整个项目大概是这样的

20200418200924

上图是创建应用后通过 git clone 下来的工程结构,应用名称为 youzanyun-demo,默认生成有六个 module。

项目根包名:com.youzan.cloud.youzanyun.demo。

接下来按图例说明一下:

  • youzanyun-demo-api:接口声明 XXService.java、DTO 封装等,一般在这个模块里不会去依赖其他模块和第三方依赖;

  • youzanyun-demo-biz:服务实现模块,除了在该模块里写 XXServiceImpl.java 外,最主要的还会在这里编写业务扩展点实现类和消息扩展点实现类;

  • youzanyun-demo-dal:如果你的应用中用到了数据库,需要在这个模块里去写 dao、mapper 等,应用框架默认支持 druid 和 mybatis;

  • youzanyun-demo-deploy:这个模块是用来打包的,执行 mvn package 后的最终 jar 包生成模块,所以生成后不需要去改动里面的内容,改动后可能会导致发布失败;

  • youzanyun-demo-web:项目的一些 web 相关的类放在这个模块里,如 XXController.java,以及一些静态资源(js、css、页面等等);

  • youzanyun-demo-ui:前端扩展点定制需要在该目录下实现。 h5-extension,H5 定制目录;mp-extension,小程序定制目录,创建应用后默认不会有这个目录,通过开发者工具导入项目之后会自动生成。

实现电子卡券扩展点

按照说明我们要实现对应的扩展点,需要在如下目录中去创建对应的后端业务扩展点,也就是 youzanyun-demo-biz\src\main\java\com.youzan.cloud.youzan.demo.biz,注意不要去修改包名称,否则可能无法加载到对应的 Bean

20200418201129

接下来,我们开始创建扩展点,这里我演示下创建电子卡券扩展点,首先我们创建一个 CreateTicketExtImplDemo 的类,然后这个类的基本结构如下

@Slf4j
@ExtensionService("createticketdemo")
public class CreateTicketExtImplDemo implements CreateTicketExtPoint {


    @Override
    public OutParam<CreateTicketResponseDTO> create(CreateTicketRequestDTO request) {
        return null;
    }
}

说下上面的 class

  • @Slf4j 这个没什么好说的,就是开启日志注解,Springboot 自带的
  • @ExtensionService 表示这个 class 是一个扩展点,这个扩展点的名称是 createticketdemo,最终会在控制台看到这个名称对应的扩展点
  • public class CreateTicketExtImplDemo implements CreateTicketExtPoint 表示这个 CreateTicketExtImplDemo 实现了 CreateTicketExtPoint 这个接口,CreateTicketExtPoint 就是创建电子卡券的扩展点接口
  • public OutParam create(CreateTicketRequestDTO request) 就是这个接口对应的方法,我们需要重写这个方法

那么,我们接下来只需要在这个方法里面写上具体的业务逻辑,然后将结果返回给有赞云就行,有赞云提供了丰富的扩展点接口,你可以参考文档 https://doc.youzanyun.com/doc#/content/EXT/0-1

以创建电子卡券接口为了,我们需要用到 2 个接口

接口或扩展点 地址
电子卡券扩展点 https://doc.youzanyun.com/doc#/content/EXT/0-1/detail/ext/753
第三方电子卡券创建接口 https://doc.youzanyun.com/doc#/content/API/1-307/detail/api/0/586

说明:

  • 可以看到电子卡券扩展点的 request 里面的有很多参数,但是这里不要以正常的 HTTP 请求逻辑去理解这个扩展点,这里面的 request 是不需要用户去传参请求的,这些参数是用户下单购买电子卡券的时候会把这些信息传到你开启的这个扩展点里面来。
  • 这个接口我们需要传入订单号、统一核销码和券码三个信息,有赞云会跟进用户自定义的卡券信息来生成卡券。

那么对应的业务逻辑基本如下:

说明

  • 用户从页面创建电子卡券类型订单
  • 订单信息通过创建电子卡券扩展点传进来
  • 获取订单号并调用第三方卡券创建接口传入该订单号、用户自定义卡券信息和券码,有赞云跟进信息生成卡券,那么在调用第三方卡券的时候我们还需要生成 token 才能去调用接口
  • 返回成功信息

最终代码如下,仅供参考,实际请根据业务需要实现

package com.youzan.cloud.youzanyun.demo.biz;

import com.alibaba.fastjson.JSON;
import com.youzan.api.rpc.annotation.ExtensionService;
import com.youzan.cloud.base.api.BifrostService;
import com.youzan.cloud.extension.api.trade.CreateTicketExtPoint;
import com.youzan.cloud.extension.param.trade.CreateTicketRequestDTO;
import com.youzan.cloud.extension.param.trade.CreateTicketResponseDTO;
import com.youzan.cloud.metadata.common.OutParam;
import com.youzan.cloud.open.sdk.common.constant.OAuthEnum;
import com.youzan.cloud.open.sdk.common.exception.SDKException;
import com.youzan.cloud.open.sdk.core.client.auth.Token;
import com.youzan.cloud.open.sdk.core.oauth.model.OAuthToken;
import com.youzan.cloud.open.sdk.gen.v3_0_1.api.YouzanTradeVirtualticketThirdCreate;
import com.youzan.cloud.open.sdk.gen.v3_0_1.model.YouzanTradeVirtualticketThirdCreateParams;
import com.youzan.cloud.open.sdk.gen.v3_0_1.model.YouzanTradeVirtualticketThirdCreateResult;
import com.youzan.cloud.youzanyun.demo.biz.util.OutParamUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@Slf4j
@ExtensionService("createticketdemo")
public class CreateTicketExtImplDemo implements CreateTicketExtPoint {
    @Resource
    private BifrostService bifrostSdkService;
    @SneakyThrows
    @Override
    public OutParam<CreateTicketResponseDTO> create(CreateTicketRequestDTO createTicketRequestDTO) {
        log.info("创建商家自有卡券, 请求体,{}", JSON.toJSONString(createTicketRequestDTO));
        CreateTicketResponseDTO createTicketResponseDTO = new CreateTicketResponseDTO();
        // 创建Token
        OAuthToken token = null;
        try {
            token = bifrostSdkService.getToken("43727705", OAuthEnum.TokenType.silent);
        } catch (SDKException e) {
            e.printStackTrace();
        }
        String accessToken = token.getAccessToken();
        log.info("获取到的token {}",accessToken);
        //调用创建电子卡券API
        YouzanTradeVirtualticketThirdCreate youzanTradeVirtualticketThirdCreate = new YouzanTradeVirtualticketThirdCreate();
        YouzanTradeVirtualticketThirdCreateParams youzanTradeVirtualticketThirdCreateParams = new YouzanTradeVirtualticketThirdCreateParams();
        youzanTradeVirtualticketThirdCreateParams.setTid(createTicketRequestDTO.getOrderNo());
        youzanTradeVirtualticketThirdCreateParams.setCode(RandomCode());
        youzanTradeVirtualticketThirdCreateParams.setTicketNos(RandomTicketNos());
        youzanTradeVirtualticketThirdCreate.setAPIParams(youzanTradeVirtualticketThirdCreateParams);
        YouzanTradeVirtualticketThirdCreateResult result = null;
        try {
            result = bifrostSdkService.invoke(youzanTradeVirtualticketThirdCreate, new Token(accessToken), YouzanTradeVirtualticketThirdCreateResult.class);
        } catch (SDKException e) {
            e.printStackTrace();
        }
        log.info("自定义电子卡券返回信息 {}",result.getMessage() + " " + result.getCode() +" "+ result.getSuccess());
        createTicketResponseDTO.setSuccess(true);
        return OutParamUtil.successResult(createTicketResponseDTO);
    }
    //生成卡券统一核销码
    public String RandomCode() {
        Random random = new Random();
        String resultCode = "";
        for (int i = 0; i < 21; i++) {
            resultCode += random.nextInt(10);
        }
        return resultCode;
    }
    //生成券码信息
    public List<String> RandomTicketNos(){
        List<String> TicketNos = new ArrayList();
        Random random = new Random();
        String  resultCode  ="";
        for (int i = 0; i < 18; i++) {
            resultCode += random.nextInt(10);
        }
        TicketNos.add(resultCode);

        return TicketNos;

    }

}

注意事项

上述代码中创建 token 部分与你直接调用 API 接口所使用的 Token 创建方式并不一样,需要特别注意

// 创建Token
    OAuthToken token = null;
    try {
        token = bifrostSdkService.getToken("43727705", OAuthEnum.TokenType.silent);
    } catch (SDKException e) {
        e.printStackTrace();
    }
    String accessToken = token.getAccessToken();
    log.info("获取到的token {}",accessToken);

上传代码并发布

我们将实现好的业务代码 push 到 git 仓库去

git add .
git commit -m '增加了电子卡券扩展点'
git push origin

当你的代码 push 到服务端后,打开有赞云控制台的开发环境下的业务配置 - 路由配置 - 交付 - 后端流程中,我们就可以看到我们实现的扩展点,我们可以看到当前扩展点的状态是未启用,我们需要点击启用,这样就会显示咋启用列表中

这里的业务标识,我们可以不用管,但是在实际的生产环境中如果你需要对特定类型的商品实现扩展点,那么你需要配置。

注意: 同一个扩展点可以实现多个,如果你开启了多个相同的扩展点,这个扩展点建议先关闭,否则可能看不到具体的效果

开启后,我们切换到应用管理 - 发布管理,我们点击发布,选择服务端,然后填写发布说明进行发布,如下所示,我们可以在列表中看到此前发布的情况

有赞云的发布环境分为两套,开发环境和生产环境,当你所处的是开发环境,你点击开发环境这个按钮就会切换到生产环境,我们要想发布到生产环境必须先保证在开发环境下是发布成功的且能够获得预期效果后才到生产环境去发布

我们先在开发环境发布,点击发布,选择发发布的类型,这里我们选择服务端,然后点击下一步,填写发布的内容,点击提交

最终提交发布的版本会在列表显示,当状态是发布成功时就表示发布成功了

20200418203321

接下来,我们可以在对应的授权测试店铺进行测试,如何判断店铺是否授权呢?我们在应用概况的店铺授权信息中点击新增 / 查看测试店铺就可以看到了

20200418203522

登录有赞微商城,在对应的授权店铺去创建一个电子卡券类型的商品,然后下单测试

当你创建完订单后会自动生成对应的电子卡券的卡券凭证,这里面就包括了券码和统一核销码

054a161ef5c327b8dc81200b868594a

当测试店铺测试没有问题后切换到有赞云后台,将环境切换到生产环境,然后按照上述发布流程发布一次,这里需要注意的是生产环境发布的版本是在开发环境中选择,你需要选择最新的版本进行发布