一、接口说明
方案为商户使用的用户提供“通用缴款支撑服务”,提供线下缴款缴款方式,通过二维码扫码主流互联网支付渠道,为缴款人提供更丰富、更灵活的缴款选择,让缴款更方便。
二、 缴款流程
2.1 商户预下单
2.1.1 说明
商户完成业务处理后,调用SDK中生成create的方法,通过商户后端对参数进行加密请求到我方后端。我方服务完成预下单后返回URL串,商户需将URL串转换为二维码,将二维码通过物理方式展现给客户。
统一接口为
com.bosssoft.sdk.model.Charge.create(chargeMap,serviceUrl,privateKey);
其中chargeMap为接口参数,见下方接口参数章节。
serviceUrl为我方提供的接口地址:
测试环境为:http://debug.epayservice.cn/thirdpay/charge/preOrder.do
privateKey为数据传输时签名加密所需使用的商户私钥。
2.2.2 接口参数
chargeMap参数内容:
属性 | 描述 | 类型 | 是否必填 | 补充 |
---|---|---|---|---|
merchant_no | 商户号 | String | 是 | |
widget_content | 订单内容 | String | 是 | 转出时需使用私钥签名 |
back_url | 后端通知地址 | String | 是 | |
charge_param | 透传参数 | String | 否 | 后台通知时,返回 |
extra | 扩展参数 | String | 否 |
widget_content参数内容(JSON):
属性 | 描述 | 类型 | 是否必填 | 补充 |
---|---|---|---|---|
merchant_no | 商户号 | String | 是 | |
merchant_order_no | 商户订单号 | String | 是 | |
amount | 订单金额 | Integer | 是 | 单位 分 |
widget_param | 控件参数 | String | 否 | 如果提供业务参数文档,则必填 不提供,则为空 |
subject | 商品标题 | String | 是 | |
body | 商品描述 | String | 否 | |
device_type | 设备类型 | String | 是 | phone |
effective_time | 有效时间 | String | 否 | 1m~15d,m-分钟,h-小时,d-天 默认当天1c,24点失效 |
version_no | 版本编码 | String | 是 | 1.0旧接口 1.1新接口 |
2.2.3 响应参数
接口返回值统一使用String类型接收,再转为相应的值集类型进行后续处理。
属性 | 描述 | 类型 | 是否必填 | 补充 |
---|---|---|---|---|
success | 返回状态 | Boolean | 是 | true:成功 false:失败 |
extraInfo | 返回跳转的信息 | String | 否 | 发生异常时字段为空 |
msg | 返回的描述信息 | String | 是 |
2.2.4 Demo
2.2 二维码展现
2.2.1 说明
商户接收到预下单生成的URL串后将其转换为二维码形式,并将二维码通过物理方式展现给缴款人。
2.2.2 推荐格式
1、码制
缴款二维码采用快速响应矩阵码(简称QR码),遵循国家标准《GB/T 18284 快速响应矩阵码》。
2、内容编码格式
数据结构的内容编码格式采用:UTF-8。
3、符号质量
(1)版本:版本5(37模块×37模块,容量134byte)以上。
(2)纠错等级:L(最大 7% 的错误能够被纠正)以上。
(3)尺寸:21mm×21mm(不含空白区)以上,最小模块尺寸不宜小于0.254mm。
(4)色彩:背景色为白色,前景色为黑色。
2.3 后台结果通知
2.3.1 说明
支付后会异步给商户后端返回通知,作为缴款的记账依据;
通过HttpClient发送POST请求。
2.3.2 接口参数
1、解析request请求,将输入流转换成StringBuffer类型的字符串,然后用私钥进行解密,调用SDK封装的统一解密方法,转成json对象,根据接口字段来获取商户对账需要的字段,如下表:
属性 | 描述 | 类型 | 是否必填 | 补充 |
---|---|---|---|---|
merchant_no | 商户号 | String | 是 | |
merchant_order_no | 商户订单号 | String | 是 | |
amount | 支付金额 | Integer | 是 | 单位 分 |
confirm_time | 缴款时间 | String | 是 | yyyy-MM-dd hh:mm:ss |
result | 支付结果 | String | 是 | 200 成功 500 失败 |
result_des | 支付结果描述 | String | 否 | 失败时填写失败原因 |
charge_param | 透传参数 | String | 否 | |
extra | 扩展参数 | String | 是 | 支付渠道channel、电子票查验einvoice_url、einvoice_data等信息 |
extra参数说明
属性 | 描述 | 类型 | 是否必填 | 补充 |
---|---|---|---|---|
channel | 缴款渠道 | String | 否 | |
channel_name | 缴款渠道名称 | String | 否 | |
channel_trade_no | 渠道订单号 | String | 否 | |
third_trade_no | 第三方订单号 | String | 否 | 微信支付第三方订单号 |
payer_id | 付款人id | String | 否 | 支付宝支付,付款人id |
bill_batch_code | 票据代码 | String | 否 | |
bill_no | 票据号码 | String | 否 | |
bill_random | 票据校验码 | String | 否 | |
einvoice_url | 电子票查看地址 | String | 否 | |
einvoice_data | 电子票数据 | String | 否 |
2、统一解密的方法
com.bosssoft.sdk.model.Message.decryptByPrivateKey(RsaStr,
privateKey);
RsaStr为1中解析出加密后的字符串;
privateKey为数据传输时签名加密所需使用的商户私钥。
2.3.3 响应参数
属性 | 描述 | 类型 | 是否必填 | 补充 |
---|---|---|---|---|
result | 响应结果 | String | 是 | 200 成功 500 失败 |
result_des | 响应结果描述 | String | 否 | 失败时填写失败原因 |
extra | 扩展参数 | String | 否 |
2.3.4 Demo
三、附录
3.1 Demo
@RequestMapping(value = “/createCharge”, method = RequestMethod.POST,produces={“text/html;charset=UTF-8;”,”application/json;”})
@ResponseBody
public String createCharge(
@RequestParam(value = “merchantno”, required = true) String merchant_no,
@RequestParam(value = “merchant_order_no”) String merchant_order_no,
@RequestParam(value = “amount”) Integer amount,
@RequestParam(value = “channel”) String channel,
@RequestParam(value = “widget_content”, required = true) String widget_content,
@RequestParam(value = “service_url”, required = true) String service_url,
HttpServletRequest request, HttpServletResponse
response) {
if (StringUtils.isEmpty(merchant_no)
&& StringUtils.isEmpty(merchant_order_no) && StringUtils.isEmpty(channel) &&
StringUtils.isEmpty(charge_param) &&
StringUtils.isEmpty(widget_content) && StringUtils.isEmpty(service_url)) {
try {
BufferedReader br
=request.getReader();
net.sf.json.JSONObject objStr=
net.sf.json.JSONObject.fromObject(br.readLine());
merchant_no = (String)
objStr.get(“merchant_no”);
merchant_order_no = (String)
objStr.get(“merchant_order_no”);
amount = (Integer)
objStr.get(“amount”);
channel = (String)
objStr.get(“channel”);
charge_param = (String)
objStr.get(“charge_param”);
widget_content = (String)
objStr.get(“widget_content”);
service_url = (String) objStr.get(“service_url”);
} catch (IOException e) {
logger.error(“获取请求参数失败{}”, e);
e.printStackTrace();
}
}
// merchant_no,channel,merchant_order_no,amount用于验证订单一致性和获取信息。
_logger.info(merchantno);
_logger.info(merchantorder_no);
_logger.info(amount);
// 支付渠道取值,用户选择支付方式点提交后,会将channel传进来
logger.info(channel);
//重要:构造chargeMap
Map
chargeMap.put(“merchantno”, merchant_no);// 商户号,应与js中传入的一致,接到的merchant_no参数
chargeMap.put(“subject”, ParamConstant.SUBJECT);//
商品标题,该参数最长为 32 个 Unicode 字符(商户根据自己的需求可选择传或不传)
chargeMap.put(“body”, ParamConstant.BODY);// 商品描述信息,该参数最长为 100 个 Unicode 字符(商户根据自己的需求可选择传或不传)
chargeMap.put(“widget_content”, widget_content);// 组装json串
chargeMap.put(“front_url”, ParamConstant.FRONT_URL);//
前端通知地址
chargeMap.put(“back_url”,ParamConstant.BACK_URL);//
后端通知地址
Map
chargeMap.put(“extra”, extra); // 扩展参数,如果有需要的话构造一个map然后将map转换成json串传入
String chargeString = “”;
String _privateKey
// 发起 create创建charge请求(参数为构造的的chargeMap,传入的controller的serviceurl)
chargeString = Charge.create(_chargeMap, service_url ,privateKey);
logger.info(chargeString);
} catch
(Exception e) {
e.printStackTrace();
}
return chargeString;
}
3.2 Demo
@RequestMapping(value = “/backnotice”, method = RequestMethod.POST)
@ResponseBody
public String backNotice(HttpServletRequest request,HttpServletResponse response) throws Exception {
_logger_.info("客户端开始接受后台回调通知...");
//从request中获取到输入流,然后解析流到StringBuffer中,获取到加密后的Stringbuffer字符串
StringBuffer stringBuffer = new StringBuffer();
try {
InputStream is = request.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String s = "";
while ((s = br.readLine()) != null) {
stringBuffer.append(s);
}
} catch (IOException e) {
e.printStackTrace();
}
String str = stringBuffer.toString(); <br /> <br />String privateKey="";//私钥赋值<br />String mes=Message.decryptByPrivateKey(str,privateKey);<br /> _logger_.info(mes);
//给予服务端响应响应
JSONObject json=new JSONObject();<br />//成功
json.put("result", "200");
_logger_.info("客户端接受后台回调通知结束...");
return json.toString();
}