| | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import com.panzhihua.applets.config.MinioUtil; |
| | | import com.panzhihua.applets.umf.UmfPayUtil; |
| | | import com.panzhihua.applets.unionpay.Refund; |
| | | import com.panzhihua.applets.unionpay.UnifiedOrder; |
| | | import com.panzhihua.common.controller.BaseController; |
| | | import com.panzhihua.common.model.vos.community.Base64File; |
| | | import com.panzhihua.common.utlis.*; |
| | |
| | | Map map=umfPayUtil.pay(orderid, DateUtils.getCurrentDateString(),openid,amount); |
| | | return R.ok(map); |
| | | } |
| | | |
| | | @ApiOperation("无水洗车下单接口") |
| | | @GetMapping("/wsPay") |
| | | public R wsPay(@RequestParam("orderid") String orderid,@RequestParam("openid")String openid,@RequestParam("amount")String amount){ |
| | | Map map=umfPayUtil.pay2(orderid, DateUtils.getCurrentDateString(),openid,amount); |
| | | return R.ok(map); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | @ApiOperation("uu洗车银联下单接口") |
| | | @GetMapping("/uuUnionpayPay") |
| | | public R uuUnionpayPay(@RequestParam("amount")String amount,@RequestParam("productId")String productId){ |
| | | String map= UnifiedOrder.sendOrder(amount,"uu洗车下单",productId); |
| | | return R.ok(map); |
| | | } |
| | | |
| | | @ApiOperation("无水洗车银联下单接口") |
| | | @GetMapping("/wsUnionpayPay") |
| | | public R wsUnionpayPay(@RequestParam("amount")String amount,@RequestParam("productId")String productId){ |
| | | String map= UnifiedOrder.sendOrder(amount,"无水洗车下单",productId); |
| | | return R.ok(map); |
| | | } |
| | | |
| | | @ApiOperation("uu洗车银联退款接口") |
| | | @GetMapping("/uuUnionpayRefund") |
| | | public R uuUnionpayRefundPay(@RequestParam("refundAmount")String refundAmount,@RequestParam("refundOrderId")String refundOrderId){ |
| | | String map= Refund.sendOrder(refundAmount,refundOrderId); |
| | | return R.ok(map); |
| | | } |
| | | |
| | | @ApiOperation("无水洗车银联退款接口") |
| | | @GetMapping("/wsUnionpayRefund") |
| | | public R wsUnionpayRefundPay(@RequestParam("refundAmount")String refundAmount,@RequestParam("refundOrderId")String refundOrderId){ |
| | | String map= Refund.sendOrder(refundAmount,refundOrderId); |
| | | return R.ok(map); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package com.panzhihua.applets.unionpay; |
| | | |
| | | import org.apache.commons.codec.binary.Base64; |
| | | import org.apache.commons.codec.digest.DigestUtils; |
| | | |
| | | import javax.crypto.Mac; |
| | | import javax.crypto.spec.SecretKeySpec; |
| | | import java.io.*; |
| | | import java.net.HttpURLConnection; |
| | | import java.net.URL; |
| | | import java.net.URLConnection; |
| | | |
| | | /** |
| | | * @author kkqiao |
| | | * 全民付移动支付小程序支付订单关闭接口 |
| | | * 说明: |
| | | * 用户创建订单之后,对未支付的订单进行关闭操作 |
| | | * 测试环境:http://58.247.0.18:29015/v1/netpay/close |
| | | * 生产环境:https://api-mop.chinaums.com/v1/netpay/close |
| | | */ |
| | | public class Close { |
| | | |
| | | static String url = "https://test-api-open.chinaums.com/v1/netpay/query"; |
| | | |
| | | public static void main(String[] args) throws Exception{ |
| | | //1. 组建请求报文 |
| | | CloseBody reqBody = new CloseBody(); |
| | | reqBody.requestTimestamp = "2019-08-09 17:12:55"; |
| | | reqBody.mid = "898460107420248"; |
| | | reqBody.tid = "00000001"; |
| | | reqBody.instMid = "MINIDEFAULT"; |
| | | reqBody.merOrderId = "101771307dc89764b477474"; |
| | | System.out.println("request body:\n"+reqBody); |
| | | |
| | | //2. 获取认证报文,timestamp为当前日期,老旧日期无法请求成功 |
| | | String authorization = getAuthorization(UnionpayContent.APPID,UnionpayContent.APPKEY, |
| | | "20190809171200","nonce",reqBody.toString()); |
| | | System.out.println("authorization:\n"+authorization); |
| | | |
| | | //3. 发送http请求,并解析返回信息 |
| | | String response = request(url,authorization,reqBody.toString()); |
| | | System.out.println("response:\n"+response); |
| | | } |
| | | |
| | | /** |
| | | * 发送http请求 |
| | | * @param url 请求url |
| | | * @param authorization 认证报文 |
| | | * @param reqBody 请求体 |
| | | * @return response |
| | | */ |
| | | static String request(String url, String authorization, String reqBody){ |
| | | String response = ""; |
| | | PrintWriter out = null; |
| | | BufferedReader in = null; |
| | | try{ |
| | | URL realUrl = new URL(url); |
| | | URLConnection conn = realUrl.openConnection(); |
| | | HttpURLConnection httpUrlConnection = (HttpURLConnection) conn; |
| | | httpUrlConnection.setRequestProperty("Content-Type", "application/json"); |
| | | httpUrlConnection.setRequestProperty("authorization",authorization); |
| | | httpUrlConnection.setDoOutput(true); |
| | | httpUrlConnection.setDoInput(true); |
| | | out = new PrintWriter(httpUrlConnection.getOutputStream()); |
| | | out.write(reqBody); |
| | | out.flush(); |
| | | httpUrlConnection.connect(); |
| | | in = new BufferedReader(new InputStreamReader(httpUrlConnection.getInputStream())); |
| | | String line; |
| | | while ((line = in.readLine()) != null) { |
| | | response += line; |
| | | } |
| | | }catch(Exception e){ |
| | | e.printStackTrace(); |
| | | } finally { |
| | | try { |
| | | if (out != null) { out.close();} |
| | | if (in != null) {in.close();} |
| | | } catch (Exception ex) { |
| | | ex.printStackTrace(); |
| | | } |
| | | } |
| | | return response; |
| | | } |
| | | |
| | | /** |
| | | * 获取签名头 |
| | | * @param appid |
| | | * @param appkey |
| | | * @param timestamp 格式:"yyyyMMddHHmmss" |
| | | * @param nonce 随机字符串, |
| | | * @param body 请求体 |
| | | * @return authorization 认证报文 |
| | | * @throws Exception |
| | | */ |
| | | static String getAuthorization(String appid, String appkey, String timestamp, String nonce, String body) throws Exception { |
| | | byte[] data = body.getBytes("utf-8"); |
| | | InputStream is = new ByteArrayInputStream(data); |
| | | String testSH = DigestUtils.sha256Hex(is); |
| | | String s1 = appid+timestamp+nonce+testSH; |
| | | Mac mac = Mac.getInstance("HmacSHA256"); |
| | | mac.init(new SecretKeySpec(appkey.getBytes("utf-8"),"HmacSHA256")); |
| | | byte[] localSignature = mac.doFinal(s1.getBytes("utf-8")); |
| | | String localSignatureStr = Base64.encodeBase64String(localSignature); |
| | | return "OPEN-BODY-SIG AppId="+"\""+appid+"\""+", Timestamp="+"\""+timestamp+"\""+", Nonce="+"\""+nonce+"\""+", Signature="+"\""+localSignatureStr+"\""; |
| | | } |
| | | |
| | | static class CloseBody{ |
| | | //消息ID |
| | | String msgId; |
| | | //报文请求时间,格式yyyy-MM-ddHH:mm:ss |
| | | String requestTimestamp; |
| | | //请求系统预留字段 |
| | | String srcReserve; |
| | | //商户号 |
| | | String mid; |
| | | //终端号 |
| | | String tid; |
| | | //业务类型 |
| | | String instMid; |
| | | //商户订单号 |
| | | String merOrderId; |
| | | |
| | | String toJson(){ |
| | | StringBuilder sb = new StringBuilder(); |
| | | sb.append("{"); |
| | | if (this.msgId != null) sb.append("\"msgId\":\"" + this.msgId + "\","); |
| | | if (this.requestTimestamp != null) sb.append("\"requestTimestamp\":\"" + this.requestTimestamp + "\","); |
| | | if (this.srcReserve != null) sb.append("\"srcReserve\":\"" + this.srcReserve + "\","); |
| | | if (this.mid != null) sb.append("\"mid\":\"" + this.mid + "\","); |
| | | if (this.tid != null) sb.append("\"tid\":\"" + this.tid + "\","); |
| | | if (this.instMid != null) sb.append("\"instMid\":\"" + this.instMid + "\","); |
| | | if (this.merOrderId != null) sb.append("\"merOrderId\":\"" + this.merOrderId + "\","); |
| | | if (sb.charAt(sb.length() - 1) == ',') |
| | | sb.deleteCharAt(sb.length() - 1); |
| | | sb.append("}"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | public String toString(){ |
| | | return this.toJson(); |
| | | } |
| | | |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.panzhihua.applets.unionpay; |
| | | |
| | | import org.apache.commons.codec.binary.Base64; |
| | | import org.apache.commons.codec.digest.DigestUtils; |
| | | |
| | | import javax.crypto.Mac; |
| | | import javax.crypto.spec.SecretKeySpec; |
| | | import java.io.*; |
| | | import java.net.HttpURLConnection; |
| | | import java.net.URL; |
| | | import java.net.URLConnection; |
| | | |
| | | /** |
| | | * @author kkqiao0 |
| | | * 全民付移动支付小程序支付订单交易查询接口 |
| | | * 说明: |
| | | * 钱包支付时,因通讯故障、服务器故障等原因,造成收银机最终没有收到支付结果通知,收银员不确定 |
| | | * 该笔支付后台处理结果,可以在收银机上发起“查询”交易,查询该笔交易订单在钱包后台的支付结果, |
| | | * 并将支付结果返回给收银机。 |
| | | * 测试环境:http://58.247.0.18:29015/v1/netpay/query |
| | | * 生产环境:https://api-mop.chinaums.com/v1/netpay/query |
| | | */ |
| | | public class Query { |
| | | static String url = "https://test-api-open.chinaums.com/v1/netpay/query"; |
| | | |
| | | public static void main(String[] args) throws Exception{ |
| | | //1. 组建请求报文 |
| | | QueryBody reqBody = new QueryBody(); |
| | | reqBody.requestTimestamp = "2019-08-09 17:32:55"; |
| | | reqBody.mid = "898460107420248"; |
| | | reqBody.tid = "00000001"; |
| | | reqBody.instMid = "MINIDEFAULT"; |
| | | reqBody.merOrderId = "101771305dc89764b477474"; |
| | | System.out.println("request body:\n"+reqBody); |
| | | |
| | | //2. 获取认证报文,timestamp为当前日期,老旧日期无法请求成功 |
| | | String authorization = getAuthorization(UnionpayContent.APPID,UnionpayContent.APPKEY,"20190809173200","nonce",reqBody.toString()); |
| | | System.out.println("authorization:\n"+authorization); |
| | | |
| | | //3. 发送http请求,并解析返回信息 |
| | | String response = request(url,authorization,reqBody.toString()); |
| | | System.out.println("response:\n"+response); |
| | | } |
| | | |
| | | /** |
| | | * 发送http请求 |
| | | * @param url 请求url |
| | | * @param authorization 认证报文 |
| | | * @param reqBody 请求体 |
| | | * @return response |
| | | */ |
| | | static String request(String url, String authorization, String reqBody){ |
| | | String response = ""; |
| | | PrintWriter out = null; |
| | | BufferedReader in = null; |
| | | try{ |
| | | URL realUrl = new URL(url); |
| | | URLConnection conn = realUrl.openConnection(); |
| | | HttpURLConnection httpUrlConnection = (HttpURLConnection) conn; |
| | | httpUrlConnection.setRequestProperty("Content-Type", "application/json"); |
| | | httpUrlConnection.setRequestProperty("authorization",authorization); |
| | | httpUrlConnection.setDoOutput(true); |
| | | httpUrlConnection.setDoInput(true); |
| | | out = new PrintWriter(httpUrlConnection.getOutputStream()); |
| | | out.write(reqBody); |
| | | out.flush(); |
| | | httpUrlConnection.connect(); |
| | | in = new BufferedReader(new InputStreamReader(httpUrlConnection.getInputStream())); |
| | | String line; |
| | | while ((line = in.readLine()) != null) { |
| | | response += line; |
| | | } |
| | | }catch(Exception e){ |
| | | e.printStackTrace(); |
| | | } finally { |
| | | try { |
| | | if (out != null) { out.close();} |
| | | if (in != null) {in.close();} |
| | | } catch (Exception ex) { |
| | | ex.printStackTrace(); |
| | | } |
| | | } |
| | | return response; |
| | | } |
| | | |
| | | /** |
| | | * 获取签名头 |
| | | * @param appid |
| | | * @param appkey |
| | | * @param timestamp 格式:"yyyyMMddHHmmss" |
| | | * @param nonce 随机字符串, |
| | | * @param body 请求体 |
| | | * @return authorization 认证报文 |
| | | * @throws Exception |
| | | */ |
| | | static String getAuthorization(String appid, String appkey, String timestamp, String nonce, String body) throws Exception { |
| | | byte[] data = body.getBytes("utf-8"); |
| | | InputStream is = new ByteArrayInputStream(data); |
| | | String testSH = DigestUtils.sha256Hex(is); |
| | | String s1 = appid+timestamp+nonce+testSH; |
| | | Mac mac = Mac.getInstance("HmacSHA256"); |
| | | mac.init(new SecretKeySpec(appkey.getBytes("utf-8"),"HmacSHA256")); |
| | | byte[] localSignature = mac.doFinal(s1.getBytes("utf-8")); |
| | | String localSignatureStr = Base64.encodeBase64String(localSignature); |
| | | return "OPEN-BODY-SIG AppId="+"\""+appid+"\""+", Timestamp="+"\""+timestamp+"\""+", Nonce="+"\""+nonce+"\""+", Signature="+"\""+localSignatureStr+"\""; |
| | | } |
| | | |
| | | static class QueryBody{ |
| | | //消息ID |
| | | String msgId; |
| | | //报文请求时间,格式yyyy-MM-ddHH:mm:ss |
| | | String requestTimestamp; |
| | | //请求系统预留字段 |
| | | String srcReserve; |
| | | //商户号 |
| | | String mid; |
| | | //终端号 |
| | | String tid; |
| | | //业务类型 |
| | | String instMid; |
| | | //商户订单号 |
| | | String merOrderId; |
| | | |
| | | String toJson(){ |
| | | StringBuilder sb = new StringBuilder(); |
| | | sb.append("{"); |
| | | if (this.msgId != null) sb.append("\"msgId\":\"" + this.msgId + "\","); |
| | | if (this.requestTimestamp != null) sb.append("\"requestTimestamp\":\"" + this.requestTimestamp + "\","); |
| | | if (this.srcReserve != null) sb.append("\"srcReserve\":\"" + this.srcReserve + "\","); |
| | | if (this.mid != null) sb.append("\"mid\":\"" + this.mid + "\","); |
| | | if (this.tid != null) sb.append("\"tid\":\"" + this.tid + "\","); |
| | | if (this.instMid != null) sb.append("\"instMid\":\"" + this.instMid + "\","); |
| | | if (this.merOrderId != null) sb.append("\"merOrderId\":\"" + this.merOrderId + "\","); |
| | | if (sb.charAt(sb.length() - 1) == ',') |
| | | sb.deleteCharAt(sb.length() - 1); |
| | | sb.append("}"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | public String toString(){ |
| | | return this.toJson(); |
| | | } |
| | | |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.panzhihua.applets.unionpay; |
| | | |
| | | import com.panzhihua.common.utlis.DateUtils; |
| | | import org.apache.commons.codec.binary.Base64; |
| | | import org.apache.commons.codec.digest.DigestUtils; |
| | | |
| | | import javax.crypto.Mac; |
| | | import javax.crypto.spec.SecretKeySpec; |
| | | import java.io.*; |
| | | import java.net.HttpURLConnection; |
| | | import java.net.URL; |
| | | import java.net.URLConnection; |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | |
| | | import static com.panzhihua.common.utlis.PayUtil.makeUUID; |
| | | |
| | | /** |
| | | * @author kkqiao |
| | | * 全民付移动支付小程序支付退款接口 |
| | | * 说明: |
| | | * 当成功交易之后一段时间内,由于买家或商户的原因需要退款时,商户可以通过本接口将支付款退还给 |
| | | * 买家,退款请求验证成功之后,银商将通知支付渠道方按照退款规则把支付款按原路退回到买家帐号 |
| | | * 上。 |
| | | * 退款订单号refundOrderId也需遵循商户订单号生成规范,即以银商分配的4位来源编号作为账单号的前 |
| | | * 4位,且在商户系统中此账单号保证唯一。总长度需大于6位,小于28位。银商的推荐规则为(无特殊情 |
| | | * 况下,建议遵守此规则): |
| | | * {来源编号(4位)}{时间(yyyyMMddmmHHssSSS)(17位)}{7位随机数} |
| | | * 测试环境:http://58.247.0.18:29015/v1/netpay/refund |
| | | * 生产环境:https://api-mop.chinaums.com/v1/netpay/refund |
| | | */ |
| | | public class Refund { |
| | | |
| | | static String url = "https://api-mop.chinaums.com/v1/netpay/refund"; |
| | | |
| | | public static String sendOrder(String refundAmount,String refundOrderId) |
| | | { |
| | | //1. 组建请求报文 |
| | | LocalDateTime time= DateUtils.getCurrentDate(); |
| | | RefundBody reqBody = new RefundBody(); |
| | | reqBody.requestTimestamp = time.format(DateUtils.format_ymdhms);// "2019-08-09 17:30:55"; |
| | | reqBody.merOrderId =UnionpayContent.TOP4+time.format(DateUtils.format_ymdhms_yyyyMMddmmHHssSSS)+makeUUID(7); |
| | | reqBody.mid =UnionpayContent.MID; |
| | | reqBody.tid = UnionpayContent.TID; |
| | | reqBody.instMid = UnionpayContent.INSTMID; |
| | | reqBody.refundAmount = refundAmount; |
| | | reqBody.refundOrderId = refundOrderId; |
| | | System.out.println("request body:\n"+reqBody); |
| | | |
| | | |
| | | //2. 获取认证报文,timestamp为当前日期,老旧日期无法请求成功 |
| | | String authorization = null; |
| | | try { |
| | | authorization = getAuthorization(UnionpayContent.APPID,UnionpayContent.APPKEY,"201908091471000","nonce",reqBody.toString()); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | return "退款失败"; |
| | | } |
| | | System.out.println("authorization:\n"+authorization); |
| | | |
| | | //3. 发送http请求,并解析返回信息 |
| | | String response = request(url,authorization,reqBody.toString()); |
| | | System.out.println("response:\n"+response); |
| | | return response; |
| | | } |
| | | |
| | | /** |
| | | * 发送http请求 |
| | | * @param url 请求url |
| | | * @param authorization 认证报文 |
| | | * @param reqBody 请求体 |
| | | * @return response |
| | | */ |
| | | static String request(String url, String authorization, String reqBody){ |
| | | String response = ""; |
| | | PrintWriter out = null; |
| | | BufferedReader in = null; |
| | | try{ |
| | | URL realUrl = new URL(url); |
| | | URLConnection conn = realUrl.openConnection(); |
| | | HttpURLConnection httpUrlConnection = (HttpURLConnection) conn; |
| | | httpUrlConnection.setRequestProperty("Content-Type", "application/json"); |
| | | httpUrlConnection.setRequestProperty("authorization",authorization); |
| | | httpUrlConnection.setDoOutput(true); |
| | | httpUrlConnection.setDoInput(true); |
| | | out = new PrintWriter(httpUrlConnection.getOutputStream()); |
| | | out.write(reqBody); |
| | | out.flush(); |
| | | httpUrlConnection.connect(); |
| | | in = new BufferedReader(new InputStreamReader(httpUrlConnection.getInputStream())); |
| | | String line; |
| | | while ((line = in.readLine()) != null) { |
| | | response += line; |
| | | } |
| | | }catch(Exception e){ |
| | | e.printStackTrace(); |
| | | } finally { |
| | | try { |
| | | if (out != null) { out.close();} |
| | | if (in != null) {in.close();} |
| | | } catch (Exception ex) { |
| | | ex.printStackTrace(); |
| | | } |
| | | } |
| | | return response; |
| | | } |
| | | |
| | | /** |
| | | * 获取签名头 |
| | | * @param appid |
| | | * @param appkey |
| | | * @param timestamp 格式:"yyyyMMddHHmmss" |
| | | * @param nonce 随机字符串, |
| | | * @param body 请求体 |
| | | * @return authorization 认证报文 |
| | | * @throws Exception |
| | | */ |
| | | static String getAuthorization(String appid, String appkey, String timestamp, String nonce, String body) throws Exception { |
| | | byte[] data = body.getBytes("utf-8"); |
| | | InputStream is = new ByteArrayInputStream(data); |
| | | String testSH = DigestUtils.sha256Hex(is); |
| | | String s1 = appid+timestamp+nonce+testSH; |
| | | Mac mac = Mac.getInstance("HmacSHA256"); |
| | | mac.init(new SecretKeySpec(appkey.getBytes("utf-8"),"HmacSHA256")); |
| | | byte[] localSignature = mac.doFinal(s1.getBytes("utf-8")); |
| | | String localSignatureStr = Base64.encodeBase64String(localSignature); |
| | | return "OPEN-BODY-SIG AppId="+"\""+appid+"\""+", Timestamp="+"\""+timestamp+"\""+", Nonce="+"\""+nonce+"\""+", Signature="+"\""+localSignatureStr+"\""; |
| | | } |
| | | |
| | | static class RefundBody{ |
| | | //消息ID |
| | | String msgId; |
| | | //报文请求时间,格式yyyy-MM-ddHH:mm:ss |
| | | String requestTimestamp; |
| | | //报文系统预留字段 |
| | | String srcReserve; |
| | | //商户订单号 |
| | | String merOrderId; |
| | | //商户号 |
| | | String mid; |
| | | //终端号 |
| | | String tid; |
| | | //业务类型 |
| | | String instMid; |
| | | //要退货的金额 |
| | | String refundAmount; |
| | | //要退款的订单号 |
| | | String refundOrderId; |
| | | //平台商户退款分账金额 |
| | | String platformAmount; |
| | | //子订单信息 |
| | | List<SubOrderItem> subOrders; |
| | | //退货说明 |
| | | String refundDesc; |
| | | |
| | | String toJson(){ |
| | | StringBuilder sb = new StringBuilder(); |
| | | sb.append("{"); |
| | | if (this.msgId != null) sb.append("\"msgId\":\"" + this.msgId + "\","); |
| | | if (this.requestTimestamp != null) sb.append("\"requestTimestamp\":\"" + this.requestTimestamp + "\","); |
| | | if (this.merOrderId != null) sb.append("\"merOrderId\":\"" + this.merOrderId + "\","); |
| | | if (this.srcReserve != null) sb.append("\"srcReserve\":\"" + this.srcReserve + "\","); |
| | | if (this.mid != null) sb.append("\"mid\":\"" + this.mid + "\","); |
| | | if (this.tid != null) sb.append("\"tid\":\"" + this.tid + "\","); |
| | | if (this.instMid != null) sb.append("\"instMid\":\"" + this.instMid + "\","); |
| | | if (this.refundAmount != null) sb.append("\"refundAmount\":\"" + this.refundAmount + "\","); |
| | | if (this.refundOrderId != null) sb.append("\"refundOrderId\":\"" + this.refundOrderId + "\","); |
| | | if (this.platformAmount != null) sb.append("\"platformAmount\":\"" + this.platformAmount + "\","); |
| | | if (this.subOrders != null && this.subOrders.size()>0) { |
| | | sb.append("\"subOrders\":["); |
| | | for(int i=0;i<subOrders.size();i++){ |
| | | sb.append(subOrders.get(i)); |
| | | sb.append(","); |
| | | } |
| | | if (sb.charAt(sb.length() - 1) == ',') |
| | | sb.deleteCharAt(sb.length() - 1); |
| | | sb.append("],"); |
| | | } |
| | | if (this.refundDesc != null) sb.append("\"refundDesc\":\"" + this.refundDesc + "\","); |
| | | if (sb.charAt(sb.length() - 1) == ',') |
| | | sb.deleteCharAt(sb.length() - 1); |
| | | sb.append("}"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | public String toString(){ |
| | | return this.toJson(); |
| | | } |
| | | static class SubOrderItem{ |
| | | //子商户号 |
| | | String mid; |
| | | //子商户分账金额 |
| | | int totalAmount; |
| | | String toJson() { |
| | | StringBuilder sb = new StringBuilder(); |
| | | sb.append("{"); |
| | | if (this.mid != null) { |
| | | sb.append("\"mid\":\"" + this.mid + "\","); |
| | | } |
| | | if (this.totalAmount != 0) { |
| | | sb.append("\"totalAmount\":\"" + this.totalAmount + "\","); |
| | | } |
| | | if (sb.charAt(sb.length() - 1) == ',') |
| | | sb.deleteCharAt(sb.length() - 1); |
| | | sb.append("}"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | public String toString(){ |
| | | return this.toJson(); |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.panzhihua.applets.unionpay; |
| | | |
| | | import org.apache.commons.codec.binary.Base64; |
| | | import org.apache.commons.codec.digest.DigestUtils; |
| | | |
| | | import javax.crypto.Mac; |
| | | import javax.crypto.spec.SecretKeySpec; |
| | | import java.io.*; |
| | | import java.net.HttpURLConnection; |
| | | import java.net.URL; |
| | | import java.net.URLConnection; |
| | | |
| | | /** |
| | | * @author kkqiao |
| | | * 全民付移动支付小程序支付退款查询接口 |
| | | * 说明: |
| | | * 钱包支付时,因通讯故障、服务器故障等原因,造成收银机最终没有收到退货结果通知,收银员不确定 |
| | | * 该笔退货后台处理结果,查询该笔退货交易订单在钱包后台的支付结果,并将退货结果返回给收银机。 |
| | | * 测试环境:http://58.247.0.18:29015/v1/netpay/refund-query |
| | | * 生产环境:https://api-mop.chinaums.com/v1/netpay/refund-query |
| | | */ |
| | | public class RefundQuery { |
| | | |
| | | static String url = "https://test-api-open.chinaums.com/v1/netpay/refund-query"; |
| | | |
| | | public static void main(String[] args) throws Exception{ |
| | | //1. 组建请求报文 |
| | | RefundQueryBody reqBody = new RefundQueryBody(); |
| | | reqBody.requestTimestamp = "2019-08-09 14:45:55"; |
| | | reqBody.mid = "898460107420248"; |
| | | reqBody.tid = "00000001"; |
| | | reqBody.instMid = "MINIDEFAULT"; |
| | | reqBody.merOrderId = "101771300dc89764b477474"; |
| | | System.out.println("request body:\n"+reqBody); |
| | | |
| | | //2. 获取认证报文,timestamp为当前日期,老旧日期无法请求成功 |
| | | String authorization = getAuthorization(UnionpayContent.APPID,UnionpayContent.APPKEY,"20190809145000","nonce",reqBody.toString()); |
| | | System.out.println("authorization:\n"+authorization); |
| | | |
| | | //3. 发送http请求,并解析返回信息 |
| | | String response = request(url,authorization,reqBody.toString()); |
| | | System.out.println("response:\n"+response); |
| | | } |
| | | |
| | | /** |
| | | * 发送http请求 |
| | | * @param url 请求url |
| | | * @param authorization 认证报文 |
| | | * @param reqBody 请求体 |
| | | * @return response |
| | | */ |
| | | static String request(String url, String authorization, String reqBody){ |
| | | String response = ""; |
| | | PrintWriter out = null; |
| | | BufferedReader in = null; |
| | | try{ |
| | | URL realUrl = new URL(url); |
| | | URLConnection conn = realUrl.openConnection(); |
| | | HttpURLConnection httpUrlConnection = (HttpURLConnection) conn; |
| | | httpUrlConnection.setRequestProperty("Content-Type", "application/json"); |
| | | httpUrlConnection.setRequestProperty("authorization",authorization); |
| | | httpUrlConnection.setDoOutput(true); |
| | | httpUrlConnection.setDoInput(true); |
| | | out = new PrintWriter(httpUrlConnection.getOutputStream()); |
| | | out.write(reqBody); |
| | | out.flush(); |
| | | httpUrlConnection.connect(); |
| | | in = new BufferedReader(new InputStreamReader(httpUrlConnection.getInputStream())); |
| | | String line; |
| | | while ((line = in.readLine()) != null) { |
| | | response += line; |
| | | } |
| | | }catch(Exception e){ |
| | | e.printStackTrace(); |
| | | } finally { |
| | | try { |
| | | if (out != null) { out.close();} |
| | | if (in != null) {in.close();} |
| | | } catch (Exception ex) { |
| | | ex.printStackTrace(); |
| | | } |
| | | } |
| | | return response; |
| | | } |
| | | |
| | | /** |
| | | * 获取签名头 |
| | | * @param appid |
| | | * @param appkey |
| | | * @param timestamp 格式:"yyyyMMddHHmmss" |
| | | * @param nonce 随机字符串, |
| | | * @param body 请求体 |
| | | * @return authorization 认证报文 |
| | | * @throws Exception |
| | | */ |
| | | static String getAuthorization(String appid, String appkey, String timestamp, String nonce, String body) throws Exception { |
| | | byte[] data = body.getBytes("utf-8"); |
| | | InputStream is = new ByteArrayInputStream(data); |
| | | String testSH = DigestUtils.sha256Hex(is); |
| | | String s1 = appid+timestamp+nonce+testSH; |
| | | Mac mac = Mac.getInstance("HmacSHA256"); |
| | | mac.init(new SecretKeySpec(appkey.getBytes("utf-8"),"HmacSHA256")); |
| | | byte[] localSignature = mac.doFinal(s1.getBytes("utf-8")); |
| | | String localSignatureStr = Base64.encodeBase64String(localSignature); |
| | | return "OPEN-BODY-SIG AppId="+"\""+appid+"\""+", Timestamp="+"\""+timestamp+"\""+", Nonce="+"\""+nonce+"\""+", Signature="+"\""+localSignatureStr+"\""; |
| | | } |
| | | |
| | | static class RefundQueryBody{ |
| | | //消息ID |
| | | String msgId; |
| | | //报文请求时间,格式yyyy-MM-ddHH:mm:ss |
| | | String requestTimestamp; |
| | | //请求系统预留字段 |
| | | String srcReserve; |
| | | //商户号 |
| | | String mid; |
| | | //终端号 |
| | | String tid; |
| | | //业务类型 |
| | | String instMid; |
| | | //商户订单号 |
| | | String merOrderId; |
| | | |
| | | String toJson(){ |
| | | StringBuilder sb = new StringBuilder(); |
| | | sb.append("{"); |
| | | if (this.msgId != null) sb.append("\"msgId\":\"" + this.msgId + "\","); |
| | | if (this.requestTimestamp != null) sb.append("\"requestTimestamp\":\"" + this.requestTimestamp + "\","); |
| | | if (this.srcReserve != null) sb.append("\"srcReserve\":\"" + this.srcReserve + "\","); |
| | | if (this.mid != null) sb.append("\"mid\":\"" + this.mid + "\","); |
| | | if (this.tid != null) sb.append("\"tid\":\"" + this.tid + "\","); |
| | | if (this.instMid != null) sb.append("\"instMid\":\"" + this.instMid + "\","); |
| | | if (this.merOrderId != null) sb.append("\"merOrderId\":\"" + this.merOrderId + "\","); |
| | | if (sb.charAt(sb.length() - 1) == ',') |
| | | sb.deleteCharAt(sb.length() - 1); |
| | | sb.append("}"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | public String toString(){ |
| | | return this.toJson(); |
| | | } |
| | | |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.panzhihua.applets.unionpay; |
| | | |
| | | import org.apache.commons.codec.binary.Base64; |
| | | import org.apache.commons.codec.digest.DigestUtils; |
| | | |
| | | import javax.crypto.Mac; |
| | | import javax.crypto.spec.SecretKeySpec; |
| | | import java.io.*; |
| | | import java.net.HttpURLConnection; |
| | | import java.net.URL; |
| | | import java.net.URLConnection; |
| | | |
| | | /** |
| | | * @author kkqiao |
| | | * 全民付移动支付小程序支付担保撤销接口 |
| | | * 说明: |
| | | * 对于担保交易(下单接口请求参数中上送了担保交易标识并置true),用户支付成功后,商户可调用此 |
| | | * 接口来进行担保撤销操作。 |
| | | * 测试环境:http://58.247.0.18:29015/v1/netpay/secure-cancel |
| | | * 生产环境:https://api-mop.chinaums.com/v1/netpay/secure-cancel |
| | | */ |
| | | public class SecureCancel { |
| | | |
| | | static String url = "https://test-api-open.chinaums.com/v1/netpay/secure-cancel"; |
| | | |
| | | public static void main(String[] args) throws Exception{ |
| | | //1. 组建请求报文 |
| | | SecureCancelBody reqBody = new SecureCancelBody(); |
| | | reqBody.requestTimestamp = "2019-08-09 17:12:55"; |
| | | reqBody.mid = "898460107420248"; |
| | | reqBody.tid = "00000001"; |
| | | reqBody.instMid = "MINIDEFAULT"; |
| | | reqBody.merOrderId = "101771305dc89764b477474"; |
| | | System.out.println("request body:\n"+reqBody); |
| | | |
| | | //2. 获取认证报文,timestamp为当前日期,老旧日期无法请求成功 |
| | | String authorization = getAuthorization(UnionpayContent.APPID,UnionpayContent.APPKEY,"20190809171200","nonce",reqBody.toString()); |
| | | System.out.println("authorization:\n"+authorization); |
| | | |
| | | //3. 发送http请求,并解析返回信息 |
| | | String response = request(url,authorization,reqBody.toString()); |
| | | System.out.println("response:\n"+response); |
| | | } |
| | | |
| | | /** |
| | | * 发送http请求 |
| | | * @param url 请求url |
| | | * @param authorization 认证报文 |
| | | * @param reqBody 请求体 |
| | | * @return response |
| | | */ |
| | | static String request(String url, String authorization, String reqBody){ |
| | | String response = ""; |
| | | PrintWriter out = null; |
| | | BufferedReader in = null; |
| | | try{ |
| | | URL realUrl = new URL(url); |
| | | URLConnection conn = realUrl.openConnection(); |
| | | HttpURLConnection httpUrlConnection = (HttpURLConnection) conn; |
| | | httpUrlConnection.setRequestProperty("Content-Type", "application/json"); |
| | | httpUrlConnection.setRequestProperty("authorization",authorization); |
| | | httpUrlConnection.setDoOutput(true); |
| | | httpUrlConnection.setDoInput(true); |
| | | out = new PrintWriter(httpUrlConnection.getOutputStream()); |
| | | out.write(reqBody); |
| | | out.flush(); |
| | | httpUrlConnection.connect(); |
| | | in = new BufferedReader(new InputStreamReader(httpUrlConnection.getInputStream())); |
| | | String line; |
| | | while ((line = in.readLine()) != null) { |
| | | response += line; |
| | | } |
| | | }catch(Exception e){ |
| | | e.printStackTrace(); |
| | | } finally { |
| | | try { |
| | | if (out != null) { out.close();} |
| | | if (in != null) {in.close();} |
| | | } catch (Exception ex) { |
| | | ex.printStackTrace(); |
| | | } |
| | | } |
| | | return response; |
| | | } |
| | | |
| | | /** |
| | | * 获取签名头 |
| | | * @param appid |
| | | * @param appkey |
| | | * @param timestamp 格式:"yyyyMMddHHmmss" |
| | | * @param nonce 随机字符串, |
| | | * @param body 请求体 |
| | | * @return authorization 认证报文 |
| | | * @throws Exception |
| | | */ |
| | | static String getAuthorization(String appid, String appkey, String timestamp, String nonce, String body) throws Exception { |
| | | byte[] data = body.getBytes("utf-8"); |
| | | InputStream is = new ByteArrayInputStream(data); |
| | | String testSH = DigestUtils.sha256Hex(is); |
| | | String s1 = appid+timestamp+nonce+testSH; |
| | | Mac mac = Mac.getInstance("HmacSHA256"); |
| | | mac.init(new SecretKeySpec(appkey.getBytes("utf-8"),"HmacSHA256")); |
| | | byte[] localSignature = mac.doFinal(s1.getBytes("utf-8")); |
| | | String localSignatureStr = Base64.encodeBase64String(localSignature); |
| | | return "OPEN-BODY-SIG AppId="+"\""+appid+"\""+", Timestamp="+"\""+timestamp+"\""+", Nonce="+"\""+nonce+"\""+", Signature="+"\""+localSignatureStr+"\""; |
| | | } |
| | | |
| | | static class SecureCancelBody{ |
| | | //消息ID |
| | | String msgId; |
| | | //报文请求时间,格式yyyy-MM-ddHH:mm:ss |
| | | String requestTimestamp; |
| | | //请求系统预留字段 |
| | | String srcReserve; |
| | | //商户号 |
| | | String mid; |
| | | //终端号 |
| | | String tid; |
| | | //业务类型 |
| | | String instMid; |
| | | //商户订单号 |
| | | String merOrderId; |
| | | |
| | | String toJson(){ |
| | | StringBuilder sb = new StringBuilder(); |
| | | sb.append("{"); |
| | | if (this.msgId != null) sb.append("\"msgId\":\"" + this.msgId + "\","); |
| | | if (this.requestTimestamp != null) sb.append("\"requestTimestamp\":\"" + this.requestTimestamp + "\","); |
| | | if (this.srcReserve != null) sb.append("\"srcReserve\":\"" + this.srcReserve + "\","); |
| | | if (this.mid != null) sb.append("\"mid\":\"" + this.mid + "\","); |
| | | if (this.tid != null) sb.append("\"tid\":\"" + this.tid + "\","); |
| | | if (this.instMid != null) sb.append("\"instMid\":\"" + this.instMid + "\","); |
| | | if (this.merOrderId != null) sb.append("\"merOrderId\":\"" + this.merOrderId + "\","); |
| | | if (sb.charAt(sb.length() - 1) == ',') |
| | | sb.deleteCharAt(sb.length() - 1); |
| | | sb.append("}"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | public String toString(){ |
| | | return this.toJson(); |
| | | } |
| | | |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.panzhihua.applets.unionpay; |
| | | |
| | | import org.apache.commons.codec.binary.Base64; |
| | | import org.apache.commons.codec.digest.DigestUtils; |
| | | |
| | | import javax.crypto.Mac; |
| | | import javax.crypto.spec.SecretKeySpec; |
| | | import java.io.*; |
| | | import java.net.HttpURLConnection; |
| | | import java.net.URL; |
| | | import java.net.URLConnection; |
| | | |
| | | /** |
| | | * @author kkqiao |
| | | * 全民付移动支付小程序支付担保完成接口 |
| | | * 说明: |
| | | * 对于担保交易(下单接口请求参数中上送了担保交易标识并置true),用户支付成功后,商户可调用此 |
| | | * 接口来进行担保完成操作。 |
| | | * 测试环境:http://58.247.0.18:29015/v1/netpay/secure-complete |
| | | * 生产环境:https://api-mop.chinaums.com/v1/netpay/secure-complete |
| | | */ |
| | | public class SecureComplete { |
| | | |
| | | static String url = "https://test-api-open.chinaums.com/v1/netpay/secure-complete"; |
| | | |
| | | public static void main(String[] args) throws Exception{ |
| | | //1. 组建请求报文 |
| | | SecureCompleteBody reqBody = new SecureCompleteBody(); |
| | | reqBody.requestTimestamp = "2019-08-09 17:12:55"; |
| | | reqBody.mid = "898460107420248"; |
| | | reqBody.tid = "00000001"; |
| | | reqBody.instMid = "MINIDEFAULT"; |
| | | reqBody.merOrderId = "101771306dc89764b477474"; |
| | | reqBody.completedAmount = "1"; |
| | | System.out.println("request body:\n"+reqBody); |
| | | |
| | | //2. 获取认证报文,timestamp为当前日期,老旧日期无法请求成功 |
| | | String authorization = getAuthorization(UnionpayContent.APPID,UnionpayContent.APPKEY,"20190809171200","nonce",reqBody.toString()); |
| | | System.out.println("authorization:\n"+authorization); |
| | | |
| | | //3. 发送http请求,并解析返回信息 |
| | | String response = request(url,authorization,reqBody.toString()); |
| | | System.out.println("response:\n"+response); |
| | | } |
| | | |
| | | /** |
| | | * 发送http请求 |
| | | * @param url 请求url |
| | | * @param authorization 认证报文 |
| | | * @param reqBody 请求体 |
| | | * @return response |
| | | */ |
| | | static String request(String url, String authorization, String reqBody){ |
| | | String response = ""; |
| | | PrintWriter out = null; |
| | | BufferedReader in = null; |
| | | try{ |
| | | URL realUrl = new URL(url); |
| | | URLConnection conn = realUrl.openConnection(); |
| | | HttpURLConnection httpUrlConnection = (HttpURLConnection) conn; |
| | | httpUrlConnection.setRequestProperty("Content-Type", "application/json"); |
| | | httpUrlConnection.setRequestProperty("authorization",authorization); |
| | | httpUrlConnection.setDoOutput(true); |
| | | httpUrlConnection.setDoInput(true); |
| | | out = new PrintWriter(httpUrlConnection.getOutputStream()); |
| | | out.write(reqBody); |
| | | out.flush(); |
| | | httpUrlConnection.connect(); |
| | | in = new BufferedReader(new InputStreamReader(httpUrlConnection.getInputStream())); |
| | | String line; |
| | | while ((line = in.readLine()) != null) { |
| | | response += line; |
| | | } |
| | | }catch(Exception e){ |
| | | e.printStackTrace(); |
| | | } finally { |
| | | try { |
| | | if (out != null) { out.close();} |
| | | if (in != null) {in.close();} |
| | | } catch (Exception ex) { |
| | | ex.printStackTrace(); |
| | | } |
| | | } |
| | | return response; |
| | | } |
| | | |
| | | /** |
| | | * 获取签名头 |
| | | * @param appid |
| | | * @param appkey |
| | | * @param timestamp 格式:"yyyyMMddHHmmss" |
| | | * @param nonce 随机字符串, |
| | | * @param body 请求体 |
| | | * @return authorization 认证报文 |
| | | * @throws Exception |
| | | */ |
| | | static String getAuthorization(String appid, String appkey, String timestamp, String nonce, String body) throws Exception { |
| | | byte[] data = body.getBytes("utf-8"); |
| | | InputStream is = new ByteArrayInputStream(data); |
| | | String testSH = DigestUtils.sha256Hex(is); |
| | | String s1 = appid+timestamp+nonce+testSH; |
| | | Mac mac = Mac.getInstance("HmacSHA256"); |
| | | mac.init(new SecretKeySpec(appkey.getBytes("utf-8"),"HmacSHA256")); |
| | | byte[] localSignature = mac.doFinal(s1.getBytes("utf-8")); |
| | | String localSignatureStr = Base64.encodeBase64String(localSignature); |
| | | return "OPEN-BODY-SIG AppId="+"\""+appid+"\""+", Timestamp="+"\""+timestamp+"\""+", Nonce="+"\""+nonce+"\""+", Signature="+"\""+localSignatureStr+"\""; |
| | | } |
| | | |
| | | static class SecureCompleteBody{ |
| | | //消息ID |
| | | String msgId; |
| | | //报文请求时间,格式yyyy-MM-ddHH:mm:ss |
| | | String requestTimestamp; |
| | | //请求系统预留字段 |
| | | String srcReserve; |
| | | //商户号 |
| | | String mid; |
| | | //终端号 |
| | | String tid; |
| | | //业务类型 |
| | | String instMid; |
| | | //商户订单号 |
| | | String merOrderId; |
| | | //担保完成金额 |
| | | String completedAmount; |
| | | |
| | | String toJson(){ |
| | | StringBuilder sb = new StringBuilder(); |
| | | sb.append("{"); |
| | | if (this.msgId != null) sb.append("\"msgId\":\"" + this.msgId + "\","); |
| | | if (this.requestTimestamp != null) sb.append("\"requestTimestamp\":\"" + this.requestTimestamp + "\","); |
| | | if (this.srcReserve != null) sb.append("\"srcReserve\":\"" + this.srcReserve + "\","); |
| | | if (this.mid != null) sb.append("\"mid\":\"" + this.mid + "\","); |
| | | if (this.tid != null) sb.append("\"tid\":\"" + this.tid + "\","); |
| | | if (this.instMid != null) sb.append("\"instMid\":\"" + this.instMid + "\","); |
| | | if (this.merOrderId != null) sb.append("\"merOrderId\":\"" + this.merOrderId + "\","); |
| | | if (this.completedAmount != null) sb.append("\"completedAmount\":\"" + this.completedAmount + "\","); |
| | | if (sb.charAt(sb.length() - 1) == ',') |
| | | sb.deleteCharAt(sb.length() - 1); |
| | | sb.append("}"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | public String toString(){ |
| | | return this.toJson(); |
| | | } |
| | | |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.panzhihua.applets.unionpay; |
| | | |
| | | import com.panzhihua.common.utlis.DateUtils; |
| | | import org.apache.commons.codec.binary.Base64; |
| | | import org.apache.commons.codec.digest.DigestUtils; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import javax.crypto.Mac; |
| | | import javax.crypto.spec.SecretKeySpec; |
| | | import java.io.*; |
| | | import java.net.HttpURLConnection; |
| | | import java.net.URL; |
| | | import java.net.URLConnection; |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | import java.util.UUID; |
| | | |
| | | import static com.panzhihua.common.utlis.PayUtil.makeUUID; |
| | | |
| | | /** |
| | | * @author kkqiao |
| | | * 全民付移动支付小程序支付下单接口 |
| | | * 说明: |
| | | * 本接口为商户的订单信息发向银商网络支付前置系统以获取支付要素商户需遵循商户订单号生成规范,即以银商分配的4位来源编号作为账单号的前4位,且在商户系统中此 |
| | | * 账单号保证唯一。总长度需大于6位,小于28位。银商的推荐规则为(无特殊情况下,建议遵守此规 |
| | | * 则): |
| | | * {来源编号(4位)}{时间(yyyyMMddmmHHssSSS)(17位)}{7位随机数} |
| | | * 微信下单成功后,使用返回数据中的miniPayRequest 即可调用支付。 |
| | | * 支付需要集成微信小程序,需要第三方自行配置。 |
| | | * 支付宝下单成功后,使用返回数据中的targetOrderId 即可调用支付。 支付需要集成支付宝支付环境, |
| | | * 需要第三方自行配置。 |
| | | * 微信: |
| | | * 测试环境:http://58.247.0.18:29015/v1/netpay/wx/unified-order |
| | | * 生产环境:https://api-mop.chinaums.com/v1/netpay/wx/unified-order |
| | | * 支付宝: |
| | | * 测试环境:http://58.247.0.18:29015/v1/netpay/trade/create |
| | | * 生产环境:https://api-mop.chinaums.com/v1/netpay/trade/create |
| | | */ |
| | | @Component |
| | | public class UnifiedOrder { |
| | | |
| | | @Value("${umf.notify_url}") |
| | | static String NOTIFYURL; |
| | | |
| | | // static String url = "https://test-api-open.chinaums.com/v1/netpay/wx/unified-order"; |
| | | static String url = "https://api-mop.chinaums.com/v1/netpay/wx/unified-order"; |
| | | |
| | | public static String sendOrder(String totalAmount,String orderDesc,String productId) |
| | | { |
| | | //1. 组建请求报文 |
| | | LocalDateTime time=DateUtils.getCurrentDate(); |
| | | UnifiedOrderBody reqBody = new UnifiedOrderBody(); |
| | | reqBody.requestTimestamp = time.format(DateUtils.format_ymdhms);// "2019-08-09 17:30:55"; |
| | | reqBody.merOrderId = UnionpayContent.TOP4+time.format(DateUtils.format_ymdhms_yyyyMMddmmHHssSSS)+makeUUID(7); |
| | | reqBody.mid = UnionpayContent.MID; |
| | | reqBody.tid = UnionpayContent.TID; |
| | | reqBody.instMid = UnionpayContent.INSTMID; |
| | | reqBody.totalAmount = totalAmount; |
| | | reqBody.secureTransaction = "true"; |
| | | reqBody.orderDesc = orderDesc; |
| | | reqBody.productId = productId; |
| | | reqBody.notifyUrl = NOTIFYURL; |
| | | System.out.println("request body:\n"+reqBody); |
| | | |
| | | //2. 获取认证报文,timestamp为当前日期,老旧日期无法请求成功 |
| | | String authorization = null; |
| | | try { |
| | | authorization = getAuthorization(UnionpayContent.APPID,UnionpayContent.APPKEY, |
| | | time.format(DateUtils.format_ymdhms_string),"nonce",reqBody.toString()); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | return "下单失败"; |
| | | } |
| | | System.out.println("authorization:\n"+authorization); |
| | | |
| | | //3. 发送http请求,并解析返回信息 |
| | | String response = request(url,authorization,reqBody.toString()); |
| | | System.out.println("response:\n"+response); |
| | | return response; |
| | | } |
| | | |
| | | /** |
| | | * 发送http请求 |
| | | * @param url 请求url |
| | | * @param authorization 认证报文 |
| | | * @param reqBody 请求体 |
| | | * @return response |
| | | */ |
| | | static String request(String url, String authorization, String reqBody){ |
| | | String response = ""; |
| | | PrintWriter out = null; |
| | | BufferedReader in = null; |
| | | try{ |
| | | URL realUrl = new URL(url); |
| | | URLConnection conn = realUrl.openConnection(); |
| | | HttpURLConnection httpUrlConnection = (HttpURLConnection) conn; |
| | | httpUrlConnection.setRequestProperty("Content-Type", "application/json"); |
| | | httpUrlConnection.setRequestProperty("authorization",authorization); |
| | | httpUrlConnection.setDoOutput(true); |
| | | httpUrlConnection.setDoInput(true); |
| | | out = new PrintWriter(httpUrlConnection.getOutputStream()); |
| | | out.write(reqBody); |
| | | out.flush(); |
| | | httpUrlConnection.connect(); |
| | | in = new BufferedReader(new InputStreamReader(httpUrlConnection.getInputStream())); |
| | | String line; |
| | | while ((line = in.readLine()) != null) { |
| | | response += line; |
| | | } |
| | | }catch(Exception e){ |
| | | e.printStackTrace(); |
| | | } finally { |
| | | try { |
| | | if (out != null) { out.close();} |
| | | if (in != null) {in.close();} |
| | | } catch (Exception ex) { |
| | | ex.printStackTrace(); |
| | | } |
| | | } |
| | | return response; |
| | | } |
| | | |
| | | /** |
| | | * 获取签名头 |
| | | * @param appid |
| | | * @param appkey |
| | | * @param timestamp 格式:"yyyyMMddHHmmss" |
| | | * @param nonce 随机字符串, |
| | | * @param body 请求体 |
| | | * @return authorization 认证报文 |
| | | * @throws Exception |
| | | */ |
| | | static String getAuthorization(String appid, String appkey, String timestamp, String nonce, String body) throws Exception { |
| | | byte[] data = body.getBytes("utf-8"); |
| | | InputStream is = new ByteArrayInputStream(data); |
| | | String testSH = DigestUtils.sha256Hex(is); |
| | | String s1 = appid+timestamp+nonce+testSH; |
| | | Mac mac = Mac.getInstance("HmacSHA256"); |
| | | mac.init(new SecretKeySpec(appkey.getBytes("utf-8"),"HmacSHA256")); |
| | | byte[] localSignature = mac.doFinal(s1.getBytes("utf-8")); |
| | | String localSignatureStr = Base64.encodeBase64String(localSignature); |
| | | return "OPEN-BODY-SIG AppId="+"\""+appid+"\""+", Timestamp="+"\""+timestamp+"\""+", Nonce="+"\""+nonce+"\""+", Signature="+"\""+localSignatureStr+"\""; |
| | | } |
| | | |
| | | static class UnifiedOrderBody{ |
| | | //消息ID |
| | | String msgId; |
| | | //报文请求时间,格式yyyy-MM-ddHH:mm:ss |
| | | String requestTimestamp; |
| | | //商户订单号 |
| | | String merOrderId; |
| | | //请求系统预留字段 |
| | | String srcReserve; |
| | | //商户号 |
| | | String mid; |
| | | //终端号 |
| | | String tid; |
| | | //业务类型 |
| | | String instMid; |
| | | //商品信息 |
| | | List<GoodsItem> goods; |
| | | //商户附加数据 |
| | | String attachedData; |
| | | //订单过期时间 |
| | | String expireTime; |
| | | //商品标记 |
| | | String goodsTag; |
| | | //商品交易单号 |
| | | String goodsTradeNo; |
| | | //账单描述 |
| | | String orderDesc; |
| | | //订单原始金额 |
| | | String originalAmount; |
| | | //商品ID |
| | | String productId; |
| | | //支付总金额 |
| | | String totalAmount; |
| | | //分账标记 |
| | | String divisionFlag; |
| | | //平台商户分账金额 |
| | | String platformAmount; |
| | | //子订单信息 |
| | | List<SubOrderItem> subOrders; |
| | | //支付结果通知地址 |
| | | String notifyUrl; |
| | | //订单展示页面 |
| | | String showUrl; |
| | | //担保交易标识 |
| | | String secureTransaction; |
| | | //用户子标识 |
| | | String tradeType; |
| | | //交易类型 |
| | | String subOpenId; |
| | | //商户用户号 |
| | | String merchantUserId; |
| | | //用户Id |
| | | String userId; |
| | | //实名认证手机号 |
| | | String mobile; |
| | | //是否需要限制信用卡支付 |
| | | String limitCreditCard; |
| | | |
| | | String toJson(){ |
| | | StringBuilder sb = new StringBuilder(); |
| | | sb.append("{"); |
| | | if (this.userId != null) sb.append("\"userId\":\"" + this.userId + "\","); |
| | | if (this.msgId != null) sb.append("\"msgId\":\"" + this.msgId + "\","); |
| | | if (this.requestTimestamp != null) sb.append("\"requestTimestamp\":\"" + this.requestTimestamp + "\","); |
| | | if (this.merOrderId != null) sb.append("\"merOrderId\":\"" + this.merOrderId + "\","); |
| | | if (this.srcReserve != null) sb.append("\"srcReserve\":\"" + this.srcReserve + "\","); |
| | | if (this.mid != null) sb.append("\"mid\":\"" + this.mid + "\","); |
| | | if (this.tid != null) sb.append("\"tid\":\"" + this.tid + "\","); |
| | | if (this.instMid != null) sb.append("\"instMid\":\"" + this.instMid + "\","); |
| | | if (this.goods != null && this.goods.size()>0) { |
| | | sb.append("\"goods\":["); |
| | | for(int i=0;i<goods.size();i++){ |
| | | sb.append(goods.get(i)); |
| | | sb.append(","); |
| | | } |
| | | if (sb.charAt(sb.length() - 1) == ',') |
| | | sb.deleteCharAt(sb.length() - 1); |
| | | sb.append("],"); |
| | | } |
| | | if (this.attachedData != null) sb.append("\"attachedData\":\"" + this.attachedData + "\","); |
| | | if (this.expireTime != null) sb.append("\"expireTime\":\"" + this.expireTime + "\","); |
| | | if (this.goodsTag != null) sb.append("\"goodsTag\":\"" + this.goodsTag + "\","); |
| | | if (this.goodsTradeNo != null) sb.append("\"goodsTradeNo\":\"" + this.goodsTradeNo + "\","); |
| | | if (this.orderDesc != null) sb.append("\"orderDesc\":\"" + this.orderDesc + "\","); |
| | | if (this.originalAmount != null) sb.append("\"originalAmount\":\"" + this.originalAmount + "\","); |
| | | if (this.productId != null) sb.append("\"productId\":\"" + this.productId + "\","); |
| | | if (this.totalAmount != null) sb.append("\"totalAmount\":\"" + this.totalAmount + "\","); |
| | | if (this.divisionFlag != null) sb.append("\"divisionFlag\":\"" + this.divisionFlag + "\","); |
| | | if (this.platformAmount != null) sb.append("\"platformAmount\":\"" + this.platformAmount + "\","); |
| | | if (this.subOrders != null && this.subOrders.size()>0) { |
| | | sb.append("\"subOrders\":["); |
| | | for(int i=0;i<subOrders.size();i++){ |
| | | sb.append(subOrders.get(i)); |
| | | sb.append(","); |
| | | } |
| | | if (sb.charAt(sb.length() - 1) == ',') |
| | | sb.deleteCharAt(sb.length() - 1); |
| | | sb.append("],"); |
| | | } |
| | | if (this.notifyUrl != null) sb.append("\"notifyUrl\":\"" + this.notifyUrl + "\","); |
| | | if (this.showUrl != null) sb.append("\"showUrl\":\"" + this.showUrl + "\","); |
| | | if (this.secureTransaction != null) sb.append("\"secureTransaction\":\"" + this.secureTransaction + "\","); |
| | | if (this.subOpenId != null) sb.append("\"subOpenId\":\"" + this.subOpenId + "\","); |
| | | if (this.tradeType != null) sb.append("\"tradeType\":\"" + this.tradeType + "\","); |
| | | if (this.merchantUserId != null) sb.append("\"merchantUserId\":\"" + this.merchantUserId + "\","); |
| | | if (this.mobile != null) sb.append("\"mobile\":\"" + this.mobile + "\","); |
| | | if (this.limitCreditCard != null) sb.append("\"limitCreditCard\":\"" + this.limitCreditCard + "\","); |
| | | if (sb.charAt(sb.length() - 1) == ',') |
| | | sb.deleteCharAt(sb.length() - 1); |
| | | sb.append("}"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | public String toString(){ |
| | | return this.toJson(); |
| | | } |
| | | static class GoodsItem { |
| | | //商品ID |
| | | String goodsId; |
| | | //商品名称 |
| | | String goodsName; |
| | | //商品数量 |
| | | String quantity; |
| | | //商品单价(分) |
| | | String price; |
| | | //商品分类 |
| | | String goodsCategory; |
| | | //商品说明 |
| | | String body; |
| | | //商品单位 |
| | | int unit; |
| | | //商品折扣 |
| | | int discount; |
| | | //子商户号 |
| | | String subMerchantId; |
| | | //子商户商品总额 |
| | | int subOrderAmount; |
| | | |
| | | String toJson(){ |
| | | StringBuilder sb = new StringBuilder(); |
| | | sb.append("{"); |
| | | if(this.goodsId!=null) sb.append("\"goodsId\":\""+this.goodsId+"\","); |
| | | if(this.goodsName!=null) sb.append("\"goodsName\":\""+this.goodsName+"\","); |
| | | if(this.quantity!=null) sb.append("\"quantity\":\""+this.quantity+"\","); |
| | | if(this.price!=null) sb.append("\"price\":\""+this.price+"\","); |
| | | if(this.goodsCategory!=null) sb.append("\"goodsCategory\":\""+this.goodsCategory+"\","); |
| | | if(this.body!=null) sb.append("\"body\":\""+this.body+"\","); |
| | | if(this.unit!=0) sb.append("\"unit\":\""+this.unit+"\","); |
| | | if(this.discount!=0) sb.append("\"discount\":\""+this.discount+"\","); |
| | | if(this.subMerchantId!=null) sb.append("\"subMerchantId\":\""+this.subMerchantId+"\","); |
| | | if(this.subOrderAmount!=0) sb.append("\"subOrderAmount\":\""+this.subOrderAmount+"\","); |
| | | if(sb.charAt(sb.length()-1) == ',') |
| | | sb.deleteCharAt(sb.length()-1); |
| | | sb.append("}"); |
| | | return sb.toString(); |
| | | } |
| | | public String toString(){ |
| | | return this.toJson(); |
| | | } |
| | | } |
| | | static class SubOrderItem{ |
| | | //子商户号 |
| | | String mid; |
| | | //子商户分账金额 |
| | | int totalAmount; |
| | | String toJson() { |
| | | StringBuilder sb = new StringBuilder(); |
| | | sb.append("{"); |
| | | if (this.mid != null) { |
| | | sb.append("\"mid\":\"" + this.mid + "\","); |
| | | } |
| | | if (this.totalAmount != 0) { |
| | | sb.append("\"totalAmount\":\"" + this.totalAmount + "\","); |
| | | } |
| | | if (sb.charAt(sb.length() - 1) == ',') |
| | | sb.deleteCharAt(sb.length() - 1); |
| | | sb.append("}"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | public String toString(){ |
| | | return this.toJson(); |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.panzhihua.applets.unionpay; |
| | | |
| | | public class UnionpayContent |
| | | { |
| | | |
| | | public static String APPID = "8a81c1bf831e72e30185755c7a0a3156"; |
| | | public static String APPKEY = "1697b2de76d547858699a45e2420c089"; |
| | | //商户号 |
| | | public static String MID = "898510475429005"; |
| | | //终端号 |
| | | public static String TID = "50525310"; |
| | | //机构商户号 |
| | | public static String INSTMID = "MINIDEFAULT"; |
| | | //订单号前4位{来源编号(4位) |
| | | public static String TOP4 = "33ZV"; |
| | | |
| | | } |
| | |
| | | public static DateTimeFormatter format_ymdhms = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); |
| | | public static DateTimeFormatter format_ymd = DateTimeFormatter.ofPattern("yyyy-MM-dd"); |
| | | public static DateTimeFormatter format_ymdhms_string = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); |
| | | public static DateTimeFormatter format_ymdhms_yyyyMMddmmHHssSSS = DateTimeFormatter.ofPattern("(yyyyMMddmmHHssSSS"); |
| | | public static DateTimeFormatter format_ymdhms_no_signal = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); |
| | | public static SimpleDateFormat yyyyMMdd_format = new SimpleDateFormat("yyyy-MM-dd"); |
| | | public static SimpleDateFormat yyyy_MM_dd_format = new SimpleDateFormat("yyyy/MM/ddHH:mm:ss"); |