⼩程序⽀付(java后端)
1.开发⼯具:
idea+springcloud+web开发⼯具
2.开发环境:
java+maven
3.开发前准备:
3.1 所需材料
⼩程序的appid,APPsecret,⽀付商户号(mch_id),商户密钥(key),付款⽤户的openid。
3.2 开发模式
本次开发采⽤的开发模式是:普通模式,适⽤于有⾃⼰开发团队或外包开发商的直连商户收款。开发者申请⾃⼰的appid和mch_id,两者需具备绑定关系,以此来使⽤⽀付提供的开放接⼝,对⽤户提供服务。
开发 java
⼀、控制层 PaymentController.java
/**
* 预⽀付Api
* 统⼀下单接⼝
* @param openId
* @return
*/
@ApiOperation("预⽀付1")
@ApiImplicitParams({
@ApiImplicitParam(name = "openId",value = "⽤户openId")
})
@PostMapping(value = {"jsapipays"})
public ResponseEntity jsapipays(@RequestParam String openId) {
Condition usercondition = new Condition(User.class);
User user=userService.findByCondition(usercondition,null).get(0);
//通过⽤户ID查询蓝⽛订单
Condition bizBluetoothOrderC=new Condition(BizBluetoothOrder.class);
List<BizBluetoothOrder> bizBluetoothOrderlist = bizBluetoothOrderService.findByCondition(bizBluetoothOrderC,null);
if(bizBluetoothOrderlist.isEmpty()){
return failResult("订单不存在!");
}
BizBluetoothOrder bizBluetoothOrder = (0);
Map jsapi = wxPayService.OrderSn(),"18.0" ,openId);
return successResult(jsapi);
}
⼆、service层
/**
* ⼩程序⽀付
* @param orderNum
* @param openId
* @return
*/
Map jsapi2(String orderNum , String total_fee, String openId);
三、实现类
* 统⼀下单开始⽅法1
* @param orderNum
* @param total_fee
* @param openId
* @return
*/
@Override
public Map jsapi2(String orderNum , String total_fee, String openId) {
try {
log.info("订单号=="+orderNum);
//拼接统⼀下单地址参数
SortedMap<String,String> paraMap = new TreeMap();
paraMap.put("appid", WXConstEnum.appId);
paraMap.put("body", "⽀付订单");
paraMap.put("mch_id", h_id);
paraMap.put("nonce_str", WxPayUtils.makeUUID(32).toUpperCase());
paraMap.put("signType",WXConstEnum.SIGNTYPE);
paraMap.put("openid", openId);
paraMap.put("out_trade_no",orderNum);//订单号商户系统内部订单号,要求32个字符内,只能是数字、⼤⼩写字母_-|*且在同⼀个商户号下唯⼀ paraMap.put("spbill_create_ip", LocalIp());
paraMap.put("total_fee", total_fee);
paraMap.put("timeStamp", CurrentTimeStamp());
paraMap.put("trade_type",WXConstEnum.TRADETYPE);
paraMap.put("notify_url",ify_url);// 此路径是服务器调⽤⽀付结果通知路径随意写
String sign = ateSignature(paraMap, WXConstEnum.key).toUpperCase();
paraMap.put("sign", sign);
String xml = WxPayUtils.mapToXml(paraMap);//将所有参数(map)转xml格式
log.info("xml源串 = " + xml);
/
/ 统⼀下单地址 h.weixin.qq/pay/unifiedorder
String xmlStr = HttpUtils.sendPost(WXConstEnum.pay_url, xml);//发送post请求"统⼀下单接⼝"返回预⽀付id:prepay_id
log.info("返回xmlStr = " + xmlStr);
//以下内容是返回前端页⾯的json数据
String prepay_id = "";//预⽀付id
if (xmlStr.indexOf("SUCCESS") != -1) {
Map<String, String> map = lToMap(xmlStr);
prepay_id = ("prepay_id");
}
Map<String, String> payMap = new HashMap<String, String>();
payMap.put("appId", WXConstEnum.appId);
payMap.put("timeStamp", CurrentTimeStamp());
payMap.put("nonceStr", WxPayUtils.makeUUID(32));
payMap.put("signType", "MD5");
String paySign = ateSignature(paraMap, WXConstEnum.key).toUpperCase();
payMap.put("paySign", paySign);
payMap.put("package", "prepay_id=" + prepay_id);
return payMap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
四、调⽤统⼀下单的接⼝参数类WXConstEnum.java
* TODO 替换成⾃⼰的参数
*/
//⼩程序appid
public static String appId = "wx34118d54080e5555";
//商户号
public static String mch_id="1612911113";
//⽀付的商户密钥
public static final String key = "50c01580a2824d48a48d94e9f6b046fb";
//⽀付成功后的服务器回调url
public static final String notify_url="shopdev.lyproduct/lyshop-app/app/orderapi/miniNotify"; //签名⽅式
public static final String SIGNTYPE = "MD5";
//交易类型
public static final String TRADETYPE = "JSAPI";
//统⼀下单接⼝地址
public static final String pay_url = "h.weixin.qq/pay/unifiedorder";
//⽀付返回状态码
public static final String SUCCESS = "SUCCESS";
五、WxPayUtils.java 需要⽤到的⼯具类 官⽅⽂档会有提供SDK
/**
* XML格式字符串转换为Map
*
* @param strXML XML字符串
* @return XML数据转换后的Map
* @throws Exception
*/
public static Map<String, String> xmlToMap(String strXML) throws Exception {
try {
Map<String, String> data = new HashMap<String, String>();
DocumentBuilderFactory documentBuilderFactory = wInstance(); DocumentBuilder documentBuilder = wDocumentBuilder();
InputStream stream = new Bytes("UTF-8"));
org.w3c.dom.Document doc = documentBuilder.parse(stream);
NodeList nodeList = DocumentElement().getChildNodes();
for (int idx = 0; idx < Length(); ++idx) {
Node node = nodeList.item(idx);
if (NodeType() == Node.ELEMENT_NODE) {
org.w3c.dom.Element element = (org.w3c.dom.Element) node;
data.NodeName(), TextContent());
}
}
try {
stream.close();
} catch (Exception ex) {
// do nothing
}
return data;
} catch (Exception ex) {
throw ex;
}
}
/**
* 将Map转换为XML格式的字符串
*
* @param data Map类型数据
* @return XML格式的字符串
* @return XML格式的字符串
* @throws Exception
*/
public static String mapToXml(SortedMap<String, String> data) throws Exception {
DocumentBuilderFactory documentBuilderFactory = wInstance();
//防⽌XXE攻击
documentBuilderFactory.setXIncludeAware(false);
documentBuilderFactory.setExpandEntityReferences(false);
DocumentBuilder documentBuilder= wDocumentBuilder();
org.w3c.dom.Document document = wDocument();
org.w3c.dom.Element root = ateElement("xml");
document.appendChild(root);
for (String key: data.keySet()) {
String value = (key);
if (value == null) {
value = "";
}
value = im();
org.w3c.dom.Element filed = ateElement(key);
filed.ateTextNode(value));
root.appendChild(filed);
}
TransformerFactory tf = wInstance();
Transformer transformer = tf.newTransformer();
DOMSource source = new DOMSource(document);
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
String output = Buffer().toString();
try {
writer.close();
}
catch (Exception ex) {
}
return output;
}
/**
* ⽣成签名
*
* @param data 待签名数据
* @param key API密钥
* @return 签名
*/
public static String generateSignature(final Map<String, String> data, String key) throws Exception {
return generateSignature(data, key, WXPayConstants.SignType.MD5);
}
/**
* ⽣成签名. 注意,若含有sign_type字段,必须和signType参数保持⼀致。
*
* @param data 待签名数据
* @param key API密钥
* @param signType 签名⽅式
* @return 签名
*/
public static String generateSignature(final Map<String, String> data, String key, WXPayConstants.SignType signType) throws Exception { Set<String> keySet = data.keySet();
String[] keyArray = Array(new String[keySet.size()]);
Arrays.sort(keyArray);
StringBuilder sb = new StringBuilder();
for (String k : keyArray) {
if (k.equals(WXPayConstants.FIELD_SIGN)) {
continue;
}
if ((k).trim().length() > 0) // 参数值为空,则不参与签名
sb.append(k).append("=").(k).trim()).append("&");
}
sb.append("key=").append(key);
if (WXPayConstants.SignType.MD5.equals(signType)) {
return String()).toUpperCase();
}
else if (WXPayConstants.SignType.HMACSHA256.equals(signType)) {
return String(), key);
}
else {
throw new Exception(String.format("Invalid sign_type: %s", signType));
}
}
/**
* ⽣成 MD5
*
* @param data 待处理数据
* @return MD5结果
*/
public static String MD5(String data) throws Exception {
MessageDigest md = Instance("MD5");
byte[] array = md.Bytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.HexString((item & 0xFF) | 0x100).substring(1, 3));
}
String().toUpperCase();
}
/**
* ⽣成 HMACSHA256
* @param data 待处理数据
* @param key 密钥
* @return 加密结果
* @throws Exception
*/
public static String HMACSHA256(String data, String key) throws Exception {
Mac sha256_HMAC = Instance("HmacSHA256");
SecretKeySpec secret_key = new Bytes("UTF-8"), "HmacSHA256"); sha256_HMAC.init(secret_key);
byte[] array = sha256_HMAC.Bytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.HexString((item & 0xFF) | 0x100).substring(1, 3));有趣的java小程序
}
String().toUpperCase();
}
/**
* 获取有序map
* @param map
* @return
*/
public static SortedMap<String,String> getSortedMap(Map<String,String> map){
SortedMap<String, String> sortedMap = new TreeMap<>();
Iterator<String> it = map.keySet().iterator();
while (it.hasNext()){
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论