一、接口说明

方案为商户使用的用户提供“通用缴款支撑服务”,提供线下缴款缴款方式,通过二维码扫码主流互联网支付渠道,为缴款人提供更丰富、更灵活的缴款选择,让缴款更方便。

二、 缴款流程

image.png

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

详见3.1部分

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.2部分

三、附录

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 = new HashMap();
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 extra = new HashMap();
chargeMap.put(“extra”, extra); // 扩展参数,如果有需要的话构造一个map然后将map转换成json串传入
String chargeString = “”;
String _privateKey
= “”;//私钥赋值 try{
// 发起 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 {

  1. _logger_.info("客户端开始接受后台回调通知...");
  2. //从request中获取到输入流,然后解析流到StringBuffer中,获取到加密后的Stringbuffer字符串
  3. StringBuffer stringBuffer = new StringBuffer();
  4. try {
  5. InputStream is = request.getInputStream();
  6. InputStreamReader isr = new InputStreamReader(is);
  7. BufferedReader br = new BufferedReader(isr);
  8. String s = "";
  9. while ((s = br.readLine()) != null) {
  10. stringBuffer.append(s);
  11. }
  12. } catch (IOException e) {
  13. e.printStackTrace();
  14. }
  15. String str = stringBuffer.toString(); <br /> <br />String privateKey="";//私钥赋值<br />String mes=Message.decryptByPrivateKey(str,privateKey);<br /> _logger_.info(mes);
  16. //给予服务端响应响应
  17. JSONObject json=new JSONObject();<br />//成功
  18. json.put("result", "200");
  19. _logger_.info("客户端接受后台回调通知结束...");
  20. return json.toString();

}