|
|
@ -1,430 +1,430 @@ |
|
|
|
//package com.ccsens.util;
|
|
|
|
//
|
|
|
|
//import cn.hutool.core.util.ObjectUtil;
|
|
|
|
//import cn.hutool.core.util.StrUtil;
|
|
|
|
//import lombok.Data;
|
|
|
|
//import org.apache.commons.codec.digest.DigestUtils;
|
|
|
|
//
|
|
|
|
//import java.io.ByteArrayInputStream;
|
|
|
|
//import java.io.UnsupportedEncodingException;
|
|
|
|
//import java.net.ConnectException;
|
|
|
|
//import java.util.*;
|
|
|
|
//
|
|
|
|
//@Data
|
|
|
|
//class GetUserInfoException extends RuntimeException{
|
|
|
|
// private int code;
|
|
|
|
// public GetUserInfoException(int code,String message){
|
|
|
|
// super(message);
|
|
|
|
// this.code = code;
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
//@Data
|
|
|
|
//class PayException extends RuntimeException{
|
|
|
|
// private int code;
|
|
|
|
// public PayException(int code,String message){
|
|
|
|
// super(message);
|
|
|
|
// this.code = code;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// public PayException(String message){
|
|
|
|
// super(message);
|
|
|
|
// this.code = -1;
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
//public class WechatUtil {
|
|
|
|
//
|
|
|
|
// /**
|
|
|
|
// * 被Jasckson使用的内部类 必须是static的
|
|
|
|
// */
|
|
|
|
// public static class WechatUser {
|
|
|
|
// public String openid;
|
|
|
|
// public String session_key;
|
|
|
|
// public String unionid;
|
|
|
|
// public String errcode;
|
|
|
|
// public String errmsg;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// /**
|
|
|
|
// * Access_Token
|
|
|
|
// */
|
|
|
|
// public static class WechatToken{
|
|
|
|
// public String access_token;
|
|
|
|
// public Long expires_in;
|
|
|
|
// public String errcode;
|
|
|
|
// public String errmsg;
|
|
|
|
// public Date create_at;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// /**
|
|
|
|
// * Get wx code
|
|
|
|
// */
|
|
|
|
// public static class WechatCode{
|
|
|
|
// public String scene;
|
|
|
|
// public String page;
|
|
|
|
// public Integer width;
|
|
|
|
// public Boolean auto_color;
|
|
|
|
// public Boolean line_color;
|
|
|
|
// public Boolean is_hyaline;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// /**
|
|
|
|
// * Prepare pay
|
|
|
|
// */
|
|
|
|
// public static class PreparePayBean{
|
|
|
|
// public String appid;//小程序ID
|
|
|
|
// public String mch_id;//商户号
|
|
|
|
// public String device_info;//设备号
|
|
|
|
// public String nonce_str;//随机字符串
|
|
|
|
// public String sign;//签名
|
|
|
|
// public String sign_type; //签名类型
|
|
|
|
// public String body;//商品描述
|
|
|
|
// public String detail;//商品详情
|
|
|
|
// public String attach;//附加数据
|
|
|
|
// public String out_trade_no;//商户订单号
|
|
|
|
// public String fee_type;//货币类型
|
|
|
|
// public Integer total_fee; //金额(分)
|
|
|
|
// public String spbill_create_ip;//终端IP
|
|
|
|
// public String time_start;//交易起始时间
|
|
|
|
// public String time_expire;//交易结束时间
|
|
|
|
// public String goods_tag;//商品标记
|
|
|
|
// public String notify_url;//通知地址
|
|
|
|
// public String trade_type;//交易类型
|
|
|
|
// public String product_id;//商品id
|
|
|
|
// public String limit_pay;//指定支付方式
|
|
|
|
// public String openid;//用户标识
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// /**
|
|
|
|
// * Prepare pay result
|
|
|
|
// */
|
|
|
|
// public static class PreparePayResultBean{
|
|
|
|
// public String return_code;
|
|
|
|
// public String return_msg;
|
|
|
|
// public String result_code;
|
|
|
|
// public String prepay_id;
|
|
|
|
// public String err_code;
|
|
|
|
// public String err_code_des;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// /**
|
|
|
|
// * Prepare pay resign
|
|
|
|
// */
|
|
|
|
// public static class PreparePayReSignBean{
|
|
|
|
// public String nonceStr;
|
|
|
|
// public String _package;
|
|
|
|
// public long timeStamp;
|
|
|
|
// public String paySign;
|
|
|
|
// public String signType;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// private static final String URL_LOGIN
|
|
|
|
// = "https://api.weixin.qq.com/sns/jscode2session?appid=%1$s&secret=%2$s&js_code=%3$s&grant_type=%4$s";
|
|
|
|
// private static final String URL_GET_ACCESS_TOKEN
|
|
|
|
// = "https://api.weixin.qq.com/cgi-bin/token?grant_type=%1$s&appid=%2$s&secret=%3$s";
|
|
|
|
// private static final String URL_GET_WX_CODE_A
|
|
|
|
// = "https://api.weixin.qq.com/wxa/getwxacode?access_token=%1$s";
|
|
|
|
// private static final String URL_GET_WX_CODE_B
|
|
|
|
// = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%1$s";
|
|
|
|
// private static final String URL_GET_WX_CODE_C
|
|
|
|
// = "https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=%1$s";
|
|
|
|
// private static final String URL_PREPARE_PAY
|
|
|
|
// = "https://api.mch.weixin.qq.com/pay/unifiedorder";
|
|
|
|
// private static final String URL_PAY_TO_USR_WX
|
|
|
|
// = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
|
|
|
|
// private static final String URL_PAY_TO_USR_BANK
|
|
|
|
// = "https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank";
|
|
|
|
//
|
|
|
|
// private static final String appid = "wx356e01c7eb01d55d";
|
|
|
|
// private static final String secret = "83149f3e151d9532f1d2eb76ca10722b";
|
|
|
|
// private static final String mchid = "1513955071";
|
|
|
|
// private static final String key = "5a689a2d6b8c4ff499c23d998fde0941"; //商户平台key
|
|
|
|
//
|
|
|
|
// /**
|
|
|
|
// * 小程序登陆,根据code获取用户信息(openid,sessionKey,)
|
|
|
|
// * @param code
|
|
|
|
// * @return
|
|
|
|
// * @throws ConnectException
|
|
|
|
// * @throws Exception
|
|
|
|
// */
|
|
|
|
// public static WechatUser getUserInfo(String code) throws Exception {
|
|
|
|
// String response = null;
|
|
|
|
// WechatUser wechatUser = null;
|
|
|
|
// String url_login = String.format(URL_LOGIN, appid, secret, code, "authorization_code");
|
|
|
|
//
|
|
|
|
// try {
|
|
|
|
// response = HttpsUtil.httpsRequest(url_login, "GET", null);
|
|
|
|
// wechatUser = JacksonUtil.jsonToBean(response, WechatUser.class);
|
|
|
|
// }catch (Exception e){
|
|
|
|
// throw new GetUserInfoException(-1,e.getMessage());
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// if(wechatUser == null) {
|
|
|
|
// throw new GetUserInfoException(-1, "Get UserInfoByCode failed.");
|
|
|
|
// }
|
|
|
|
// if(!StrUtil.isEmpty(wechatUser.errcode)) {
|
|
|
|
// throw new GetUserInfoException(Integer.valueOf(wechatUser.errcode), wechatUser.errmsg);
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// return wechatUser;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// /**
|
|
|
|
// * 获取Access_token
|
|
|
|
// * @return
|
|
|
|
// * @throws Exception
|
|
|
|
// */
|
|
|
|
// public static WechatToken getAccessToken() throws Exception {
|
|
|
|
// String response = null;
|
|
|
|
// WechatToken wechatToken = null;
|
|
|
|
// String url = String.format(URL_GET_ACCESS_TOKEN,"client_credential",appid,secret);
|
|
|
|
//
|
|
|
|
// response = HttpsUtil.httpsRequest(url,"GET",null);
|
|
|
|
// if(StrUtil.isEmpty(response)) {
|
|
|
|
// return null;
|
|
|
|
// }
|
|
|
|
// wechatToken = JacksonUtil.jsonToBean(response,WechatToken.class);
|
|
|
|
// wechatToken.create_at = new Date();
|
|
|
|
// return wechatToken;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// /**
|
|
|
|
// * 获取小程序二维码/小程序码
|
|
|
|
// * @return
|
|
|
|
// * @throws Exception
|
|
|
|
// */
|
|
|
|
// public static void getWxCode(String page,String scene,String path) throws Exception {
|
|
|
|
// WechatToken wechatToken = getAccessToken();
|
|
|
|
// String url = String.format(URL_GET_WX_CODE_B,wechatToken.access_token);
|
|
|
|
//
|
|
|
|
// WechatCode wechatCode = new WechatCode();
|
|
|
|
// wechatCode.page = page;
|
|
|
|
// wechatCode.scene = scene;
|
|
|
|
//
|
|
|
|
// String postStr = JacksonUtil.beanToJson(wechatCode);
|
|
|
|
// System.out.println(postStr);
|
|
|
|
//
|
|
|
|
// HttpsUtil.httpsRequest(url,"POST",postStr,path);
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// /**
|
|
|
|
// * 统一下单
|
|
|
|
// */
|
|
|
|
// public static PreparePayReSignBean preparePay(String openid,String out_trade_no,String body,int total_fee,String spbill_create_ip,
|
|
|
|
// String notify_url) throws Exception {
|
|
|
|
// PreparePayBean preparePayBean = new PreparePayBean();
|
|
|
|
// preparePayBean.appid = appid;
|
|
|
|
// preparePayBean.mch_id = mchid;
|
|
|
|
// preparePayBean.openid = openid;
|
|
|
|
// preparePayBean.total_fee = total_fee;
|
|
|
|
// preparePayBean.out_trade_no = out_trade_no;
|
|
|
|
// preparePayBean.body = new String(body.getBytes("ISO-8859-1"),"UTF-8");//以utf-8编码放入paymentPo,微信支付要求字符编码统一采用UTF-8字符编码
|
|
|
|
// //preparePayBean.body = new String("聊天密码小程序-充值");
|
|
|
|
// preparePayBean.spbill_create_ip = spbill_create_ip;
|
|
|
|
// preparePayBean.notify_url = notify_url;
|
|
|
|
// preparePayBean.trade_type = "JSAPI";
|
|
|
|
// preparePayBean.nonce_str = createNonceStr();
|
|
|
|
//
|
|
|
|
// // 把请求参数打包成数组
|
|
|
|
// Map<String,Object> sParaTemp = new HashMap();
|
|
|
|
// sParaTemp.put("appid", preparePayBean.appid);
|
|
|
|
// sParaTemp.put("mch_id", preparePayBean.mch_id);
|
|
|
|
// sParaTemp.put("openid", preparePayBean.openid);
|
|
|
|
// sParaTemp.put("total_fee",preparePayBean.total_fee + "");
|
|
|
|
// sParaTemp.put("out_trade_no", preparePayBean.out_trade_no);
|
|
|
|
// sParaTemp.put("body", preparePayBean.body);
|
|
|
|
// sParaTemp.put("spbill_create_ip", preparePayBean.spbill_create_ip);
|
|
|
|
// sParaTemp.put("notify_url",preparePayBean.notify_url);
|
|
|
|
// sParaTemp.put("trade_type", preparePayBean.trade_type);
|
|
|
|
// sParaTemp.put("nonce_str", preparePayBean.nonce_str);
|
|
|
|
//
|
|
|
|
// preparePayBean.sign = createSign(sParaTemp);
|
|
|
|
//
|
|
|
|
// String reqrXml = JacksonUtil.beanToXml(preparePayBean,"xml");
|
|
|
|
// String respXml = HttpsUtil.httpsRequest(URL_PREPARE_PAY,"POST",reqrXml);
|
|
|
|
//
|
|
|
|
// System.out.println("---------------PreparePay Request Xml-----------------");
|
|
|
|
// System.out.println(reqrXml);
|
|
|
|
// System.out.println("---------------PreparePay Response Xml-----------------");
|
|
|
|
// System.out.println(respXml);
|
|
|
|
// System.out.println("---------------PreparePay end-----------------");
|
|
|
|
//
|
|
|
|
// PreparePayResultBean resultBean = null;
|
|
|
|
// PreparePayReSignBean reSignBean = new PreparePayReSignBean();
|
|
|
|
// resultBean = JacksonUtil.xmlToBean(new ByteArrayInputStream(respXml.getBytes()),PreparePayResultBean.class);
|
|
|
|
//
|
|
|
|
// if(ObjectUtil.isNull(resultBean)) {
|
|
|
|
// throw new PayException("PreparePay 返回的resultBean为空");
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// if(!StrUtil.isEmpty(resultBean.return_code)
|
|
|
|
// && !StrUtil.isEmpty(resultBean.result_code)){
|
|
|
|
// if(resultBean.result_code.equals("SUCCESS") && resultBean.return_code.equals(resultBean.result_code)){
|
|
|
|
// reSignBean.nonceStr = createNonceStr();
|
|
|
|
// reSignBean._package = "prepay_id="+resultBean.prepay_id;
|
|
|
|
// reSignBean.timeStamp = System.currentTimeMillis() / 1000;
|
|
|
|
// reSignBean.signType = "MD5";
|
|
|
|
//
|
|
|
|
// // 把请求参数打包成数组
|
|
|
|
// sParaTemp = new HashMap();
|
|
|
|
// sParaTemp.put("appId", appid);
|
|
|
|
// sParaTemp.put("package", reSignBean._package);
|
|
|
|
// sParaTemp.put("nonceStr", reSignBean.nonceStr);
|
|
|
|
// sParaTemp.put("signType", reSignBean.signType);
|
|
|
|
// sParaTemp.put("timeStamp",reSignBean.timeStamp + "");
|
|
|
|
//
|
|
|
|
// reSignBean.paySign = createSign(sParaTemp);
|
|
|
|
//
|
|
|
|
// return reSignBean;
|
|
|
|
// }else{
|
|
|
|
// throw new PayException("[" + resultBean.err_code + "]"
|
|
|
|
// + resultBean.err_code_des);
|
|
|
|
// }
|
|
|
|
// }else {
|
|
|
|
// throw new PayException(resultBean.return_msg);
|
|
|
|
// }
|
|
|
|
// //return null;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// /**
|
|
|
|
// * Create Sign
|
|
|
|
// * @param sParaTemp
|
|
|
|
// * @return
|
|
|
|
// */
|
|
|
|
// public static String createSign(Map<String,Object> sParaTemp){
|
|
|
|
// // 除去数组中的空值和签名参数
|
|
|
|
// Map sPara = paraFilter(sParaTemp);
|
|
|
|
// String prestr = createLinkString(sPara); // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
|
|
|
|
// //MD5运算生成签名
|
|
|
|
// String sign = sign(prestr, key, "utf-8").toUpperCase();
|
|
|
|
// return sign;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// /**
|
|
|
|
// * 除去数组中的空值和签名参数
|
|
|
|
// * @param sArray 签名参数组
|
|
|
|
// * @return 去掉空值与签名参数后的新签名参数组
|
|
|
|
// */
|
|
|
|
// private static Map paraFilter(Map<String,Object> sArray) {
|
|
|
|
// Map result = new HashMap();
|
|
|
|
// if (sArray == null || sArray.size() <= 0) {
|
|
|
|
// return result;
|
|
|
|
// }
|
|
|
|
// for (String key : sArray.keySet()) {
|
|
|
|
// String value = "" + sArray.get(key);
|
|
|
|
// if (StrUtil.isEmpty(value) || key.equalsIgnoreCase("sign") || key.equalsIgnoreCase("sign_type")) {
|
|
|
|
// continue;
|
|
|
|
// }
|
|
|
|
// result.put(key, value);
|
|
|
|
// }
|
|
|
|
// return result;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// /**
|
|
|
|
// * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
|
|
|
|
// * @param params 需要排序并参与字符拼接的参数组
|
|
|
|
// * @return 拼接后字符串
|
|
|
|
// */
|
|
|
|
// private static String createLinkString(Map<String,String> params) {
|
|
|
|
// List<String> keys = new ArrayList(params.keySet());
|
|
|
|
// Collections.sort(keys);
|
|
|
|
// String prestr = "";
|
|
|
|
// for (int i = 0; i < keys.size(); i++) {
|
|
|
|
// String key = keys.get(i);
|
|
|
|
// String value = params.get(key);
|
|
|
|
// if (i == keys.size() - 1) {// 拼接时,不包括最后一个&字符
|
|
|
|
// prestr = prestr + key + "=" + value;
|
|
|
|
// } else {
|
|
|
|
// prestr = prestr + key + "=" + value + "&";
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// return prestr;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// /**
|
|
|
|
// * 签名字符串
|
|
|
|
// * @param text 需要签名的字符串
|
|
|
|
// * @param key 密钥
|
|
|
|
// * @param input_charset 编码格式
|
|
|
|
// * @return 签名结果
|
|
|
|
// */
|
|
|
|
// private static String sign(String text, String key, String input_charset) {
|
|
|
|
// text = text + "&key=" + key;
|
|
|
|
// return DigestUtils.md5Hex(getContentBytes(text, input_charset));
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// /**
|
|
|
|
// * @param content
|
|
|
|
// * @param charset
|
|
|
|
// * @return
|
|
|
|
// * @throws
|
|
|
|
// * @throws UnsupportedEncodingException
|
|
|
|
// */
|
|
|
|
// private static byte[] getContentBytes(String content, String charset) {
|
|
|
|
// if (charset == null || "".equals(charset)) {
|
|
|
|
// return content.getBytes();
|
|
|
|
// }
|
|
|
|
// try {
|
|
|
|
// return content.getBytes(charset);
|
|
|
|
// } catch (UnsupportedEncodingException e) {
|
|
|
|
// throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// private static String createNonceStr(){
|
|
|
|
// return UUID.randomUUID().toString().replace("-","");
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// public static Map<String,Object> payToUsrWx(
|
|
|
|
// String partner_trade_no,String openid,int total_fee,String desc,String spbill_create_ip)
|
|
|
|
// throws Exception{
|
|
|
|
// //1.构造请求字符串
|
|
|
|
// Map<String,Object> reqMap = new HashMap<String,Object>();
|
|
|
|
// reqMap.put("mch_appid",appid);
|
|
|
|
// reqMap.put("mchid",mchid);
|
|
|
|
// //reqMap.put("device_info",null); //不能添加空字段,Jackson会生成闭包xml <device_info/>导致签名失败
|
|
|
|
// reqMap.put("nonce_str",createNonceStr());
|
|
|
|
// reqMap.put("partner_trade_no",partner_trade_no);
|
|
|
|
// reqMap.put("openid",openid);
|
|
|
|
// reqMap.put("check_name","NO_CHECK");
|
|
|
|
// //reqMap.put("re_user_name",null);
|
|
|
|
// reqMap.put("amount",total_fee + "");
|
|
|
|
// reqMap.put("desc",desc);
|
|
|
|
// reqMap.put("spbill_create_ip",spbill_create_ip);
|
|
|
|
// reqMap.put("sign",createSign(reqMap));
|
|
|
|
//
|
|
|
|
// //2.发送付款请求
|
|
|
|
// String reqrXml = JacksonUtil.mapToXml(reqMap,"xml");
|
|
|
|
// String respXml = HttpsUtil.httpsRequest(URL_PAY_TO_USR_WX,"POST",reqrXml,
|
|
|
|
// WebConstant.PATH_WX_CRET,mchid);
|
|
|
|
// System.out.println("---------------PayToUsrWx Request Xml-----------------");
|
|
|
|
// System.out.println(reqrXml);
|
|
|
|
// System.out.println("---------------PayToUsrWx Response Xml-----------------");
|
|
|
|
// System.out.println(respXml);
|
|
|
|
// System.out.println("---------------PayToUsrWx end-----------------");
|
|
|
|
//
|
|
|
|
// //3.判断成功失败
|
|
|
|
// Map<String,Object> respMap = JacksonUtil.xmlToMap(new ByteArrayInputStream(respXml.getBytes()));
|
|
|
|
// String return_code,result_code;
|
|
|
|
// return_code = (String) respMap.get("return_code");
|
|
|
|
// result_code = (String) respMap.get("result_code");
|
|
|
|
//
|
|
|
|
// if(!StrUtil.isEmpty(return_code) && !StrUtil.isEmpty(result_code)){
|
|
|
|
// if(return_code.equals("SUCCESS") && return_code.equals(result_code)){
|
|
|
|
// return respMap;
|
|
|
|
// }else{
|
|
|
|
// throw new PayException("[" + respMap.get("err_code") + "]"
|
|
|
|
// + respMap.get("err_code_des"));
|
|
|
|
// }
|
|
|
|
// }else {
|
|
|
|
// throw new PayException((String) respMap.get("return_msg"));
|
|
|
|
// }
|
|
|
|
// //return null;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// public static Map<String,String> payToUsrBank(){
|
|
|
|
// //Fix Me
|
|
|
|
// return null;
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
package com.ccsens.util; |
|
|
|
|
|
|
|
import cn.hutool.core.util.ObjectUtil; |
|
|
|
import cn.hutool.core.util.StrUtil; |
|
|
|
import lombok.Data; |
|
|
|
import org.apache.commons.codec.digest.DigestUtils; |
|
|
|
|
|
|
|
import java.io.ByteArrayInputStream; |
|
|
|
import java.io.UnsupportedEncodingException; |
|
|
|
import java.net.ConnectException; |
|
|
|
import java.util.*; |
|
|
|
|
|
|
|
@Data |
|
|
|
class GetUserInfoException extends RuntimeException{ |
|
|
|
private int code; |
|
|
|
public GetUserInfoException(int code,String message){ |
|
|
|
super(message); |
|
|
|
this.code = code; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@Data |
|
|
|
class PayException extends RuntimeException{ |
|
|
|
private int code; |
|
|
|
public PayException(int code,String message){ |
|
|
|
super(message); |
|
|
|
this.code = code; |
|
|
|
} |
|
|
|
|
|
|
|
public PayException(String message){ |
|
|
|
super(message); |
|
|
|
this.code = -1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public class WechatUtil { |
|
|
|
|
|
|
|
/** |
|
|
|
* 被Jasckson使用的内部类 必须是static的 |
|
|
|
*/ |
|
|
|
public static class WechatUser { |
|
|
|
public String openid; |
|
|
|
public String session_key; |
|
|
|
public String unionid; |
|
|
|
public String errcode; |
|
|
|
public String errmsg; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Access_Token |
|
|
|
*/ |
|
|
|
public static class WechatToken{ |
|
|
|
public String access_token; |
|
|
|
public Long expires_in; |
|
|
|
public String errcode; |
|
|
|
public String errmsg; |
|
|
|
public Date create_at; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Get wx code |
|
|
|
*/ |
|
|
|
public static class WechatCode{ |
|
|
|
public String scene; |
|
|
|
public String page; |
|
|
|
public Integer width; |
|
|
|
public Boolean auto_color; |
|
|
|
public Boolean line_color; |
|
|
|
public Boolean is_hyaline; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Prepare pay |
|
|
|
*/ |
|
|
|
public static class PreparePayBean{ |
|
|
|
public String appid;//小程序ID
|
|
|
|
public String mch_id;//商户号
|
|
|
|
public String device_info;//设备号
|
|
|
|
public String nonce_str;//随机字符串
|
|
|
|
public String sign;//签名
|
|
|
|
public String sign_type; //签名类型
|
|
|
|
public String body;//商品描述
|
|
|
|
public String detail;//商品详情
|
|
|
|
public String attach;//附加数据
|
|
|
|
public String out_trade_no;//商户订单号
|
|
|
|
public String fee_type;//货币类型
|
|
|
|
public Integer total_fee; //金额(分)
|
|
|
|
public String spbill_create_ip;//终端IP
|
|
|
|
public String time_start;//交易起始时间
|
|
|
|
public String time_expire;//交易结束时间
|
|
|
|
public String goods_tag;//商品标记
|
|
|
|
public String notify_url;//通知地址
|
|
|
|
public String trade_type;//交易类型
|
|
|
|
public String product_id;//商品id
|
|
|
|
public String limit_pay;//指定支付方式
|
|
|
|
public String openid;//用户标识
|
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Prepare pay result |
|
|
|
*/ |
|
|
|
public static class PreparePayResultBean{ |
|
|
|
public String return_code; |
|
|
|
public String return_msg; |
|
|
|
public String result_code; |
|
|
|
public String prepay_id; |
|
|
|
public String err_code; |
|
|
|
public String err_code_des; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Prepare pay resign |
|
|
|
*/ |
|
|
|
public static class PreparePayReSignBean{ |
|
|
|
public String nonceStr; |
|
|
|
public String _package; |
|
|
|
public long timeStamp; |
|
|
|
public String paySign; |
|
|
|
public String signType; |
|
|
|
} |
|
|
|
|
|
|
|
private static final String URL_LOGIN |
|
|
|
= "https://api.weixin.qq.com/sns/jscode2session?appid=%1$s&secret=%2$s&js_code=%3$s&grant_type=%4$s"; |
|
|
|
private static final String URL_GET_ACCESS_TOKEN |
|
|
|
= "https://api.weixin.qq.com/cgi-bin/token?grant_type=%1$s&appid=%2$s&secret=%3$s"; |
|
|
|
private static final String URL_GET_WX_CODE_A |
|
|
|
= "https://api.weixin.qq.com/wxa/getwxacode?access_token=%1$s"; |
|
|
|
private static final String URL_GET_WX_CODE_B |
|
|
|
= "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%1$s"; |
|
|
|
private static final String URL_GET_WX_CODE_C |
|
|
|
= "https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=%1$s"; |
|
|
|
private static final String URL_PREPARE_PAY |
|
|
|
= "https://api.mch.weixin.qq.com/pay/unifiedorder"; |
|
|
|
private static final String URL_PAY_TO_USR_WX |
|
|
|
= "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"; |
|
|
|
private static final String URL_PAY_TO_USR_BANK |
|
|
|
= "https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank"; |
|
|
|
|
|
|
|
private static final String appid = "wx356e01c7eb01d55d"; |
|
|
|
private static final String secret = "83149f3e151d9532f1d2eb76ca10722b"; |
|
|
|
private static final String mchid = "1513955071"; |
|
|
|
private static final String key = "5a689a2d6b8c4ff499c23d998fde0941"; //商户平台key
|
|
|
|
|
|
|
|
/** |
|
|
|
* 小程序登陆,根据code获取用户信息(openid,sessionKey,) |
|
|
|
* @param code |
|
|
|
* @return |
|
|
|
* @throws ConnectException |
|
|
|
* @throws Exception |
|
|
|
*/ |
|
|
|
public static WechatUser getUserInfo(String code) throws Exception { |
|
|
|
String response = null; |
|
|
|
WechatUser wechatUser = null; |
|
|
|
String url_login = String.format(URL_LOGIN, appid, secret, code, "authorization_code"); |
|
|
|
|
|
|
|
try { |
|
|
|
response = HttpsUtil.httpsRequest(url_login, "GET", null); |
|
|
|
wechatUser = JacksonUtil.jsonToBean(response, WechatUser.class); |
|
|
|
}catch (Exception e){ |
|
|
|
throw new GetUserInfoException(-1,e.getMessage()); |
|
|
|
} |
|
|
|
|
|
|
|
if(wechatUser == null) { |
|
|
|
throw new GetUserInfoException(-1, "Get UserInfoByCode failed."); |
|
|
|
} |
|
|
|
if(!StrUtil.isEmpty(wechatUser.errcode)) { |
|
|
|
throw new GetUserInfoException(Integer.valueOf(wechatUser.errcode), wechatUser.errmsg); |
|
|
|
} |
|
|
|
|
|
|
|
return wechatUser; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 获取Access_token |
|
|
|
* @return |
|
|
|
* @throws Exception |
|
|
|
*/ |
|
|
|
public static WechatToken getAccessToken() throws Exception { |
|
|
|
String response = null; |
|
|
|
WechatToken wechatToken = null; |
|
|
|
String url = String.format(URL_GET_ACCESS_TOKEN,"client_credential",appid,secret); |
|
|
|
|
|
|
|
response = HttpsUtil.httpsRequest(url,"GET",null); |
|
|
|
if(StrUtil.isEmpty(response)) { |
|
|
|
return null; |
|
|
|
} |
|
|
|
wechatToken = JacksonUtil.jsonToBean(response,WechatToken.class); |
|
|
|
wechatToken.create_at = new Date(); |
|
|
|
return wechatToken; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 获取小程序二维码/小程序码 |
|
|
|
* @return |
|
|
|
* @throws Exception |
|
|
|
*/ |
|
|
|
public static void getWxCode(String page,String scene,String path) throws Exception { |
|
|
|
WechatToken wechatToken = getAccessToken(); |
|
|
|
String url = String.format(URL_GET_WX_CODE_B,wechatToken.access_token); |
|
|
|
|
|
|
|
WechatCode wechatCode = new WechatCode(); |
|
|
|
wechatCode.page = page; |
|
|
|
wechatCode.scene = scene; |
|
|
|
|
|
|
|
String postStr = JacksonUtil.beanToJson(wechatCode); |
|
|
|
System.out.println(postStr); |
|
|
|
|
|
|
|
HttpsUtil.httpsRequest(url,"POST",postStr,path); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 统一下单 |
|
|
|
*/ |
|
|
|
public static PreparePayReSignBean preparePay(String openid,String out_trade_no,String body,int total_fee,String spbill_create_ip, |
|
|
|
String notify_url) throws Exception { |
|
|
|
PreparePayBean preparePayBean = new PreparePayBean(); |
|
|
|
preparePayBean.appid = appid; |
|
|
|
preparePayBean.mch_id = mchid; |
|
|
|
preparePayBean.openid = openid; |
|
|
|
preparePayBean.total_fee = total_fee; |
|
|
|
preparePayBean.out_trade_no = out_trade_no; |
|
|
|
preparePayBean.body = new String(body.getBytes("ISO-8859-1"),"UTF-8");//以utf-8编码放入paymentPo,微信支付要求字符编码统一采用UTF-8字符编码
|
|
|
|
//preparePayBean.body = new String("聊天密码小程序-充值");
|
|
|
|
preparePayBean.spbill_create_ip = spbill_create_ip; |
|
|
|
preparePayBean.notify_url = notify_url; |
|
|
|
preparePayBean.trade_type = "JSAPI"; |
|
|
|
preparePayBean.nonce_str = createNonceStr(); |
|
|
|
|
|
|
|
// 把请求参数打包成数组
|
|
|
|
Map<String,Object> sParaTemp = new HashMap(); |
|
|
|
sParaTemp.put("appid", preparePayBean.appid); |
|
|
|
sParaTemp.put("mch_id", preparePayBean.mch_id); |
|
|
|
sParaTemp.put("openid", preparePayBean.openid); |
|
|
|
sParaTemp.put("total_fee",preparePayBean.total_fee + ""); |
|
|
|
sParaTemp.put("out_trade_no", preparePayBean.out_trade_no); |
|
|
|
sParaTemp.put("body", preparePayBean.body); |
|
|
|
sParaTemp.put("spbill_create_ip", preparePayBean.spbill_create_ip); |
|
|
|
sParaTemp.put("notify_url",preparePayBean.notify_url); |
|
|
|
sParaTemp.put("trade_type", preparePayBean.trade_type); |
|
|
|
sParaTemp.put("nonce_str", preparePayBean.nonce_str); |
|
|
|
|
|
|
|
preparePayBean.sign = createSign(sParaTemp); |
|
|
|
|
|
|
|
String reqrXml = JacksonUtil.beanToXml(preparePayBean,"xml"); |
|
|
|
String respXml = HttpsUtil.httpsRequest(URL_PREPARE_PAY,"POST",reqrXml); |
|
|
|
|
|
|
|
System.out.println("---------------PreparePay Request Xml-----------------"); |
|
|
|
System.out.println(reqrXml); |
|
|
|
System.out.println("---------------PreparePay Response Xml-----------------"); |
|
|
|
System.out.println(respXml); |
|
|
|
System.out.println("---------------PreparePay end-----------------"); |
|
|
|
|
|
|
|
PreparePayResultBean resultBean = null; |
|
|
|
PreparePayReSignBean reSignBean = new PreparePayReSignBean(); |
|
|
|
resultBean = JacksonUtil.xmlToBean(new ByteArrayInputStream(respXml.getBytes()),PreparePayResultBean.class); |
|
|
|
|
|
|
|
if(ObjectUtil.isNull(resultBean)) { |
|
|
|
throw new PayException("PreparePay 返回的resultBean为空"); |
|
|
|
} |
|
|
|
|
|
|
|
if(!StrUtil.isEmpty(resultBean.return_code) |
|
|
|
&& !StrUtil.isEmpty(resultBean.result_code)){ |
|
|
|
if(resultBean.result_code.equals("SUCCESS") && resultBean.return_code.equals(resultBean.result_code)){ |
|
|
|
reSignBean.nonceStr = createNonceStr(); |
|
|
|
reSignBean._package = "prepay_id="+resultBean.prepay_id; |
|
|
|
reSignBean.timeStamp = System.currentTimeMillis() / 1000; |
|
|
|
reSignBean.signType = "MD5"; |
|
|
|
|
|
|
|
// 把请求参数打包成数组
|
|
|
|
sParaTemp = new HashMap(); |
|
|
|
sParaTemp.put("appId", appid); |
|
|
|
sParaTemp.put("package", reSignBean._package); |
|
|
|
sParaTemp.put("nonceStr", reSignBean.nonceStr); |
|
|
|
sParaTemp.put("signType", reSignBean.signType); |
|
|
|
sParaTemp.put("timeStamp",reSignBean.timeStamp + ""); |
|
|
|
|
|
|
|
reSignBean.paySign = createSign(sParaTemp); |
|
|
|
|
|
|
|
return reSignBean; |
|
|
|
}else{ |
|
|
|
throw new PayException("[" + resultBean.err_code + "]" |
|
|
|
+ resultBean.err_code_des); |
|
|
|
} |
|
|
|
}else { |
|
|
|
throw new PayException(resultBean.return_msg); |
|
|
|
} |
|
|
|
//return null;
|
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Create Sign |
|
|
|
* @param sParaTemp |
|
|
|
* @return |
|
|
|
*/ |
|
|
|
public static String createSign(Map<String,Object> sParaTemp){ |
|
|
|
// 除去数组中的空值和签名参数
|
|
|
|
Map sPara = paraFilter(sParaTemp); |
|
|
|
String prestr = createLinkString(sPara); // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
|
|
|
|
//MD5运算生成签名
|
|
|
|
String sign = sign(prestr, key, "utf-8").toUpperCase(); |
|
|
|
return sign; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 除去数组中的空值和签名参数 |
|
|
|
* @param sArray 签名参数组 |
|
|
|
* @return 去掉空值与签名参数后的新签名参数组 |
|
|
|
*/ |
|
|
|
private static Map paraFilter(Map<String,Object> sArray) { |
|
|
|
Map result = new HashMap(); |
|
|
|
if (sArray == null || sArray.size() <= 0) { |
|
|
|
return result; |
|
|
|
} |
|
|
|
for (String key : sArray.keySet()) { |
|
|
|
String value = "" + sArray.get(key); |
|
|
|
if (StrUtil.isEmpty(value) || key.equalsIgnoreCase("sign") || key.equalsIgnoreCase("sign_type")) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
result.put(key, value); |
|
|
|
} |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串 |
|
|
|
* @param params 需要排序并参与字符拼接的参数组 |
|
|
|
* @return 拼接后字符串 |
|
|
|
*/ |
|
|
|
private static String createLinkString(Map<String,String> params) { |
|
|
|
List<String> keys = new ArrayList(params.keySet()); |
|
|
|
Collections.sort(keys); |
|
|
|
String prestr = ""; |
|
|
|
for (int i = 0; i < keys.size(); i++) { |
|
|
|
String key = keys.get(i); |
|
|
|
String value = params.get(key); |
|
|
|
if (i == keys.size() - 1) {// 拼接时,不包括最后一个&字符
|
|
|
|
prestr = prestr + key + "=" + value; |
|
|
|
} else { |
|
|
|
prestr = prestr + key + "=" + value + "&"; |
|
|
|
} |
|
|
|
} |
|
|
|
return prestr; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 签名字符串 |
|
|
|
* @param text 需要签名的字符串 |
|
|
|
* @param key 密钥 |
|
|
|
* @param input_charset 编码格式 |
|
|
|
* @return 签名结果 |
|
|
|
*/ |
|
|
|
private static String sign(String text, String key, String input_charset) { |
|
|
|
text = text + "&key=" + key; |
|
|
|
return DigestUtils.md5Hex(getContentBytes(text, input_charset)); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @param content |
|
|
|
* @param charset |
|
|
|
* @return |
|
|
|
* @throws |
|
|
|
* @throws UnsupportedEncodingException |
|
|
|
*/ |
|
|
|
private static byte[] getContentBytes(String content, String charset) { |
|
|
|
if (charset == null || "".equals(charset)) { |
|
|
|
return content.getBytes(); |
|
|
|
} |
|
|
|
try { |
|
|
|
return content.getBytes(charset); |
|
|
|
} catch (UnsupportedEncodingException e) { |
|
|
|
throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private static String createNonceStr(){ |
|
|
|
return UUID.randomUUID().toString().replace("-",""); |
|
|
|
} |
|
|
|
|
|
|
|
public static Map<String,Object> payToUsrWx( |
|
|
|
String partner_trade_no,String openid,int total_fee,String desc,String spbill_create_ip) |
|
|
|
throws Exception{ |
|
|
|
//1.构造请求字符串
|
|
|
|
Map<String,Object> reqMap = new HashMap<String,Object>(); |
|
|
|
reqMap.put("mch_appid",appid); |
|
|
|
reqMap.put("mchid",mchid); |
|
|
|
//reqMap.put("device_info",null); //不能添加空字段,Jackson会生成闭包xml <device_info/>导致签名失败
|
|
|
|
reqMap.put("nonce_str",createNonceStr()); |
|
|
|
reqMap.put("partner_trade_no",partner_trade_no); |
|
|
|
reqMap.put("openid",openid); |
|
|
|
reqMap.put("check_name","NO_CHECK"); |
|
|
|
//reqMap.put("re_user_name",null);
|
|
|
|
reqMap.put("amount",total_fee + ""); |
|
|
|
reqMap.put("desc",desc); |
|
|
|
reqMap.put("spbill_create_ip",spbill_create_ip); |
|
|
|
reqMap.put("sign",createSign(reqMap)); |
|
|
|
|
|
|
|
//2.发送付款请求
|
|
|
|
String reqrXml = JacksonUtil.mapToXml(reqMap,"xml"); |
|
|
|
String respXml = HttpsUtil.httpsRequest(URL_PAY_TO_USR_WX,"POST",reqrXml, |
|
|
|
WebConstant.PATH_WX_CRET,mchid); |
|
|
|
System.out.println("---------------PayToUsrWx Request Xml-----------------"); |
|
|
|
System.out.println(reqrXml); |
|
|
|
System.out.println("---------------PayToUsrWx Response Xml-----------------"); |
|
|
|
System.out.println(respXml); |
|
|
|
System.out.println("---------------PayToUsrWx end-----------------"); |
|
|
|
|
|
|
|
//3.判断成功失败
|
|
|
|
Map<String,Object> respMap = JacksonUtil.xmlToMap(new ByteArrayInputStream(respXml.getBytes())); |
|
|
|
String return_code,result_code; |
|
|
|
return_code = (String) respMap.get("return_code"); |
|
|
|
result_code = (String) respMap.get("result_code"); |
|
|
|
|
|
|
|
if(!StrUtil.isEmpty(return_code) && !StrUtil.isEmpty(result_code)){ |
|
|
|
if(return_code.equals("SUCCESS") && return_code.equals(result_code)){ |
|
|
|
return respMap; |
|
|
|
}else{ |
|
|
|
throw new PayException("[" + respMap.get("err_code") + "]" |
|
|
|
+ respMap.get("err_code_des")); |
|
|
|
} |
|
|
|
}else { |
|
|
|
throw new PayException((String) respMap.get("return_msg")); |
|
|
|
} |
|
|
|
//return null;
|
|
|
|
} |
|
|
|
|
|
|
|
public static Map<String,String> payToUsrBank(){ |
|
|
|
//Fix Me
|
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|