外卖全自动接单打印机,如果要实现自动接单打印,就必须对接饿了么开放平台。优声云外卖打印机对接来饿了么开放平台,可以实现饿了么订单自动接单,自动打印。
饿了么为开发者开放的平台API,可以实现用户在饿了么平台下单后,将订单推送至商家自有平台或第三方平台,从而达到订单的统一管理,自动接单,自动打印。
创建应用
首先在 饿了么商家开放平台创建应用并提交审核。
完成后饿了么会给一个沙箱环境:
这里会给出测试账号,用这个测试账号直接登普通版饿了么商家APP就行,并不是想支付宝那样单独做一个沙箱APP。
需要注意的是:
- H5网页和电脑端可能会打不开,我开始是饿了么商家版登录测试账号,设置->店名能够正常访问。
- 测试店铺的默认地址都在上海东平国家公园,所以要下单的话首先需要设置收货地址。
- 店铺是虚的,但是买家账号可以用真实账号,这个还是挺方便的。
配置应用
首先,回调地址是一定要写的,所有的API都需要商户鉴权,基于OAuth,所以必须要有一个回调接受Code并换取token本地保存。
然后是推送Url,用来接受订单推送消息,饿了么平台有两种推送方式,一种就是基于推送Url的HTTP,另一种是全双工Socket,并且附带SDK,所以这个推送URL是可选项。
推送消息的话看情况选。
配置回调
设置完回调地址后,我们需要在应用中写接受饿了么商家Code的API,注意这个Code只能用一次,不能重复用一个Code换token。
@RequestMapping("/eleme/callback")
public Response elemeCallback(String code) throws ServiceException {
Token token = elemeService.getTokenByCode(code);
redisTemplate.opsForValue().set("accessToken",token.getAccessToken());
redisTemplate.opsForValue().set("tokenExpires",String.valueOf(System.currentTimeMillis() + token.getExpires()));
redisTemplate.opsForValue().set("refreshToken",String.valueOf(token.getRefreshToken()));
return Response.success("授权成功");
}
拿到token直接用Redis落地存储。
这里用了一个小技巧,首先是为了便于调试,我需要将这个回调接口暴露到公网,这样饿了么就可以直接访问到我的开发环境,我也就不用编译打包到测试环境,做下内网穿透,网上有很多工具。
但是饿了么的回调有个要求就是必须要支持HTTPS访问,但是我的内网穿透工具没有ssl支持。
所以我用了自己的域名+SSL+反向代理到内网穿透工具的域名上,这样我对自己域名的HTTPS访问被我的阿里云服务器转发到了HTTP访问的开发服务器上,满足了饿了么的要求。
调用API
拿到token存储之后就可以用SDK中的service获取商家信息了,一个例子如下:
@GetMapping("/eleme/shop")
public Response getElmeShop() throws ServiceException {
// 校验token
if (Long.valueOf(Objects.requireNonNull(redisTemplate.opsForValue().get("tokenExpires"))) < System.currentTimeMillis()){
OAuthClient client = new OAuthClient(new Config(true,this.appKey,this.appSecret));
Token token = client.getTokenByRefreshToken(redisTemplate.opsForValue().get("refreshToken"));
// 保存token
redisTemplate.opsForValue().set("accessToken",token.getAccessToken());
redisTemplate.opsForValue().set("tokenExpires",String.valueOf(System.currentTimeMillis() + token.getExpires()));
redisTemplate.opsForValue().set("refreshToken",String.valueOf(token.getRefreshToken()));
}
Token token = new Token();
token.setAccessToken(redisTemplate.opsForValue().get("accessToken"));
ShopService shopService = new ShopService(new Config(true,this.appKey,this.appSecret),token);
return Response.success(shopService.getShop(xxxxxxx));
}
因为Token有过期时间,所以访问时需要判断token是否已经过期。
refreshToken用来刷新Token
全双工订单推送
在后端应用启动的时候,就应该和饿了么建立Socket,同时应该和自有平台的前端也建立Socket连接,这样用户在饿了么下单时,消息将推送至后端,后端处理后再推送至自有平台前端。
使用饿了么的SDK,再main方法中建立连接
public static void main(String[] args) throws IOException {
SpringApplication.run(YsApplication.class, args);
ElemeService elemeService = new ElemeServiceImpl();
elemeService.setUpSocketConnection();
}
setUpSocketConnection:
Account account = new Account("xxx", "xxx");
List<Account> accounts = new ArrayList<Account>();
accounts.add(account);
eleme.openapi.ws.sdk.config.Config config = new eleme.openapi.ws.sdk.config.Config(accounts,
new BusinessHandle() {
@Override
public boolean onMessage(String message) {
//你的业务消息处理,推荐直接落地存储,不要耦合过重业务
System.out.println("收到饿了么消息");
System.out.println(message);
return true;
}
},
new ElemeSdkLogger() {
@Override
public void info(String message) {
//your info log 处理
System.out.println("收到info消息");
System.out.println(message);
}
@Override
public void error(String message) {
//your error log 处理
System.out.println("收到错误消息");
System.out.println(message);
}
}
);
try {
Bootstrap.start(config);
} catch (UnableConnectionException e) {
e.printStackTrace();
}
需要注意,饿了么的SDK中,API请求访问中有个Config类,WebSocket模块中也有一个同名Config,所以如果在一个文件中同时用到了两个Config,一定要加全路径区分。
写完后socket会随Spring Boot一起启动。
随后在APP中下单,开发环境就可以收到通知:
在没有商家鉴权时,是收不到消息的,但是这个socket也不需要用到token,所以我判断是饿了么系统判断是否下发了token以及当前时间是否在上次下发的token有效期内来决定是否推送。