软件编程
位置:首页>> 软件编程>> java编程>> java微信公众号支付开发之现金红包

java微信公众号支付开发之现金红包

作者:GCS随心  发布时间:2023-09-01 17:28:38 

标签:java,微信,红包

我们先来看看公众号发放现金红包的效果:

java微信公众号支付开发之现金红包

需要调用商户平台的接口,接口发放规则如下:

1.发送频率限制——默认1800/min
2.发送个数上限——按照默认1800/min算
3.金额上限——根据传入场景id不同默认上限不同,可以在商户平台产品设置进行设置和申请,最大不大于4999元/个
4.其他的“量”上的限制还有哪些?——用户当天的领取上限次数,默认是10
5.如果量上满足不了我们的需求,如何提高各个上限?——金额上限和用户当天领取次数上限可以在商户平台进行设置
注意-红包金额大于200时,请求参数scene_id必传,参数说明见下文。
注意2-根据监管要求,新申请商户号使用现金红包需要满足两个条件:1、入驻时间超过90天 2、连续正常交易30天。

请求Url https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack
是否需要证书 是(证书及使用说明详见商户证书)
请求方式 POST

请求数据示例:


<xml>

<sign><![CDATA[E1EE61A91C8E90F299DE6AE075D60A2D]]></sign>

<mch_billno><![CDATA[0010010404201411170000046545]]></mch_billno>

<mch_id><![CDATA[888]]></mch_id>

<wxappid><![CDATA[wxcbda96de0b165486]]></wxappid>
<send_name><![CDATA[send_name]]></send_name>
<re_openid><![CDATA[onqOjjmM1tad-3ROpncN-yUfa6uI]]></re_openid>
<total_amount><![CDATA[200]]></total_amount>
<total_num><![CDATA[1]]></total_num>
<wishing><![CDATA[恭喜发财]]></wishing>

<client_ip><![CDATA[127.0.0.1]]></client_ip>
<act_name><![CDATA[新年红包]]></act_name>
<remark><![CDATA[新年红包]]></remark>
<scene_id><![CDATA[PRODUCT_2]]></scene_id>
<consume_mch_id><![CDATA[10000097]]></consume_mch_id>
<nonce_str><![CDATA[50780e0cca98c8c8e814883e5caa672e]]></nonce_str>

<risk_info>posttime%3d123123412%26clientversion%3d234134%26mobile%3d122344545%26deviceid%3dIOS</risk_info>

</xml>

接口需要调用商户平台的证书,证书需要去商户平台下载:

java微信公众号支付开发之现金红包

然后在接口中使用证书,首先我们新建一个WeixinSSL 类


@Component
public class WeiXinSSL {

/**
 * 证书类型
 */
@Value("${werchant.storekey}")
private String storekey;

/**
 * 文件路径
 */
@Value("${werchant.ssLfile}")
private String ssLfile;

/**
 * 商户号
 */
@Value("${werchant.merchantNumber}")
private String merchantNumber;

public String getStorekey() {
 return storekey;
}

public void setStorekey(String storekey) {
 this.storekey = storekey;
}

public String getSsLfile() {
 return ssLfile;
}

public void setSsLfile(String ssLfile) {
 this.ssLfile = ssLfile;
}

public String getMerchantNumber() {
 return merchantNumber;
}

public void setMerchantNumber(String merchantNumber) {
 this.merchantNumber = merchantNumber;
}
}

封装HttpClientSSL 类实现 https 请求加证书:


@Component
public class HttpClientSSL {

@Autowired
private WeiXinSSL weiXinSSL;

// 请求超时时间(毫秒) 5秒
public static RequestConfig requestConfig;

// 响应超时时间(毫秒) 60秒
public static int HTTP_RESPONSE_TIMEOUT = 60 * 1000;

// httpClient字符编码
public static String encoding = "UTF-8";

public static RequestConfig getRequestConfig() {
 return RequestConfig.custom().setConnectTimeout(5 * 1000)
   .setConnectionRequestTimeout(HTTP_RESPONSE_TIMEOUT).build();
}

public static void setRequestConfig(RequestConfig requestConfig) {
 HttpClientSSL.requestConfig = requestConfig;
}

/**
 * https请求伪造证书
 * @return
 */
public CloseableHttpClient defaultSSLClient() {
 SSLContext sslContext = null;
 try {
  new SSLContextBuilder().loadTrustMaterial(null,new TrustStrategy(){
   @Override
   public boolean isTrusted(X509Certificate[] chain, String authType)
     throws java.security.cert.CertificateException {
    return false;
   }
  });
 } catch (NoSuchAlgorithmException | KeyStoreException e) {
  e.printStackTrace();
 }
 SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslContext);
 return HttpClients.custom().setSSLSocketFactory(factory).build();
}

/**
 * https请求加证书
 * @return
 */
public CloseableHttpClient defaultSSLClientFile() {
 if (this.weiXinSSL == null){
  return this.defaultSSLClient();
 }
 FileInputStream inputStream = null;
 KeyStore keyStore = null;
 try {
  // ssl类型
  keyStore = KeyStore.getInstance(weiXinSSL.getStorekey());
  // ssl文件
  inputStream = new FileInputStream(weiXinSSL.getSsLfile());
  // 设置ssl密码
  keyStore.load(inputStream,weiXinSSL.getMerchantNumber().toCharArray());
 } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e1) {
  e1.printStackTrace();
 } finally {
  try {
   inputStream.close();
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
 SSLContext sslContext = null;
 try {
  sslContext = SSLContexts.custom().loadKeyMaterial(keyStore,weiXinSSL.getMerchantNumber().toCharArray()).build();
 } catch (UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
  e.printStackTrace();
 }

SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1" }, null,
   SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
 return HttpClients.custom().setSSLSocketFactory(factory).build();
}

/**
 * 封装发送请求的方法
 * @throws UnsupportedEncodingException
 */
public String send(String url, String data, CloseableHttpClient closeableHttpClient)
  throws UnsupportedEncodingException {

CloseableHttpClient client = closeableHttpClient;
 HttpPost httpPost = new HttpPost(URLDecoder.decode(url, encoding));
 httpPost.addHeader("Connection", "keep-alive");
 httpPost.addHeader("Accept", "*/*");
 httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
 httpPost.addHeader("Host", "api.mch.weixin.qq.com");
 httpPost.addHeader("X-Requested-With", "XMLHttpRequest");
 httpPost.addHeader("Cache-Control", "max-age=0");
 httpPost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
 httpPost.setConfig(this.getRequestConfig());// 设置超时时间
 CloseableHttpResponse response = null;

// 参数放入
 StringEntity entity = new StringEntity(data, encoding);
 entity.setContentEncoding(encoding);
 entity.setContentType("application/xml");
 httpPost.setEntity(entity);

try {
  response = client.execute(httpPost);
  if (response.getStatusLine().getStatusCode() == 200) {
   HttpEntity httpEntity = (HttpEntity) response.getEntity();
   if (response != null) {
    return EntityUtils.toString(httpEntity,encoding);
   }
  }
 } catch (IOException e) {
  e.printStackTrace();
 }
 return null;
}

}

这样我们就封装了一个https请求加证书的实体类,接下来我们生成请求微信红包接口:
https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack 的参数签名:


/**
* 红包参数实体类
* @throws UnsupportedEncodingException
*/
@Component
public class SendRedPack implements Serializable{

/**
 *
 */
private static final long serialVersionUID = -1000489228099916099L;

private String nonce_str;// 随机字符串
private String sign;// 签名
private String mch_billno;// 商户订单号
private String mch_id;// 商户号
private String wxappid;// 公众账号
private String send_name;// 商户名称
private String re_openid;// 用户
private int total_amount;// 付款金额 单位:分
private int total_num;// 红包发放总人数
private String wishing;// 红包祝福语
private String client_ip;// Ip地址
private String act_name;// 活动名称
private String remark;// 备注
public String getNonce_str() {
 return nonce_str;
}
public void setNonce_str(String nonce_str) {
 this.nonce_str = nonce_str;
}
public String getSign() {
 return sign;
}
public void setSign(String sign) {
 this.sign = sign;
}
public String getMch_billno() {
 return mch_billno;
}
public void setMch_billno(String mch_billno) {
 this.mch_billno = mch_billno;
}
public String getMch_id() {
 return mch_id;
}
public void setMch_id(String mch_id) {
 this.mch_id = mch_id;
}
public String getWxappid() {
 return wxappid;
}
public void setWxappid(String wxappid) {
 this.wxappid = wxappid;
}
public String getSend_name() {
 return send_name;
}
public void setSend_name(String send_name) {
 this.send_name = send_name;
}
public String getRe_openid() {
 return re_openid;
}
public void setRe_openid(String re_openid) {
 this.re_openid = re_openid;
}
public int getTotal_amount() {
 return total_amount;
}
public void setTotal_amount(int total_amount) {
 this.total_amount = total_amount;
}
public int getTotal_num() {
 return total_num;
}
public void setTotal_num(int total_num) {
 this.total_num = total_num;
}
public String getWishing() {
 return wishing;
}
public void setWishing(String wishing) {
 this.wishing = wishing;
}
public String getClient_ip() {
 return client_ip;
}
public void setClient_ip(String client_ip) {
 this.client_ip = client_ip;
}
public String getAct_name() {
 return act_name;
}
public void setAct_name(String act_name) {
 this.act_name = act_name;
}
public String getRemark() {
 return remark;
}
public void setRemark(String remark) {
 this.remark = remark;
}
}

接下来是发送红包的控制器:


/**
* 领红包控制器
* @author zengliang
*/
@Controller
@RequestMapping(value="/redenveLopesReceive")
public class RedEnvelopesReceiveController {

//微信唯一标识
@Value("${weixin.appid}")
private String appid;

//微信开发者密码标识
@Value("${weixin.appsecret}")
public String appsecret;

@Autowired
private SendRedPack sendredpack;

@Autowired
private HttpClientSSL httpclientssl;

/**
 * 发送XML参数
 * @author zengliang
 */
@ResponseBody
@RequestMapping(value="/sendXml")
public String sendXml(String openid,Long redenveLopes_id
  ,String mch_billno){
 RedenveLopes redenve = redenveLopesService.findOne(redenveLopes_id);

XMLUtil xmlUtil= new XMLUtil();
 sendredpack.setAct_name(redenve.getAct_name());
 sendredpack.setNonce_str(xmlUtil.random());
 sendredpack.setRe_openid(openid);
 sendredpack.setClient_ip(redenve.getClient_ip());
 sendredpack.setMch_billno(mch_billno);
 sendredpack.setMch_id(redenve.getMch_id());
 String xx = redenve.getRemark();
 sendredpack.setRemark(StringUtils.isEmpty(xx) == false?xx:"空");
 sendredpack.setSend_name(redenve.getSend_name());
 sendredpack.setTotal_amount(redenve.getTotal_amount());
 sendredpack.setTotal_num(redenve.getTotal_num());
 sendredpack.setWishing(redenve.getWishing());
 sendredpack.setWxappid(redenve.getWxappidxx());
 //生成签名
 String params = this.createSendRedPackOrderSign(sendredpack,redenve.getStore_key());
 sendredpack.setSign(params);

xmlUtil.xstream().alias("xml",sendredpack.getClass());
 //扩展xstream,使其支持CDATA块
 String requestXml = xmlUtil.xstream().toXML(sendredpack);

String result;
 try {
  result = httpclientssl.send("https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack",requestXml,httpclientssl.defaultSSLClientFile());
  System.out.println("成功返回值"+result);
  return result;
 } catch (UnsupportedEncodingException e) {
  e.printStackTrace();
 }
 return null;
}

/**
 * 生成签名
 * @param redPack
 * @return
 */
public String createSendRedPackOrderSign(SendRedPack redPack,String storekey){
 StringBuffer sign = new StringBuffer();
 sign.append("act_name=").append(redPack.getAct_name());
 sign.append("&client_ip=").append(redPack.getClient_ip());
 sign.append("&mch_billno=").append(redPack.getMch_billno());
 sign.append("&mch_id=").append(redPack.getMch_id());
 sign.append("&nonce_str=").append(redPack.getNonce_str());
 sign.append("&re_openid=").append(redPack.getRe_openid());
 sign.append("&remark=").append(redPack.getRemark());
 sign.append("&send_name=").append(redPack.getSend_name());
 sign.append("&total_amount=").append(redPack.getTotal_amount());
 sign.append("&total_num=").append(redPack.getTotal_num());
 sign.append("&wishing=").append(redPack.getWishing());
 sign.append("&wxappid=").append(redPack.getWxappid());
 sign.append("&key=").append(storekey);
 return DigestUtils.md5Hex(sign.toString()).toUpperCase();
}

}

然后我们需要用一个解析XML的工具类实现解析微信返回的XML


/**
* 解析XML工具类
* @author zengliang
*/
@Component
public class XMLUtil {

/**
 * 解析微信返回的XML
 * @param xml
 * @return
 * @throws Exception
 */
@SuppressWarnings("unchecked")
public Map<String, String> parseXml(String xml)throws Exception {
 Map<String,String> map = new HashMap<String,String>();
 Document doc = null;
 try {
  doc = DocumentHelper.parseText(xml); // 将字符串转为XML
  Element rootElt = doc.getRootElement(); // 获取根节点
  List<Element> list = rootElt.elements();//获取根节点下所有节点
  for (Element element : list) { //遍历节点
   map.put(element.getName(), element.getText()); //节点的name为map的key,text为map的value
  }
 } catch (DocumentException e) {
  e.printStackTrace();
 } catch (Exception e) {
  e.printStackTrace();
 }
 return map;
}

/**
 * 扩展xstream,使其支持CDATA块
 */
 private XStream xstream = new XStream(new XppDriver(new NoNameCoder()) {
  @Override
  public HierarchicalStreamWriter createWriter(Writer out) {
    return new PrettyPrintWriter(out) {
    // 对所有xml节点的转换都增加CDATA标记
    boolean cdata = true;
    @Override
    @SuppressWarnings("rawtypes")
    public void startNode(String name, Class clazz) {
     super.startNode(name, clazz);
    }
    @Override
    public String encodeNode(String name) {
     return name;
    }
    @Override
    protected void writeText(QuickWriter writer, String text) {
     if (cdata) {
      writer.write("<![CDATA[");
      writer.write(text);
      writer.write("]]>");
     } else {
      writer.write(text);
     }
    }
    };
  }
 });
 private XStream inclueUnderlineXstream = new XStream(new DomDriver(null,new XmlFriendlyNameCoder("_-", "_")));
 public XStream getXstreamInclueUnderline() {
  return inclueUnderlineXstream;
 }

public XStream xstream() {
  return xstream;
 }

/**
 * 生成随机数
 * @return
 */
public String random(){
 String random = UUID.randomUUID().toString().replace("-", "");
 return random;
}
}

然后我们调用 sendXML 方法公众号就能向用户发送红包了。

来源:https://blog.csdn.net/u010088415/article/details/79942302

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com