简介:
主要流程为按照微信要求的格式准备xml发送数据,然后发送请求,微信响应后再解析返回的数据,根据返回数据再进行自己的业务操作。
注意代码中需要自己填写的部分以及证书位置要用绝对路径;
依赖:
<!-- 解析xml -->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.10</version>
</dependency>
实体类:
package com.ruoyi.project.wxuserhb.domain;
import java.io.Serializable;
/**
* 微信发放红包接口 sdkVo
*
* @author Qiu
* @date 2022-11-24 10:24
*/
public class WxRedpackSdkVo implements Serializable {
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 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 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 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;
}
}
工具类:
package com.ruoyi.project.wxuserhb.Utils;
import com.ruoyi.project.wxuserhb.domain.WxRedpackSdkVo;
import com.ruoyi.project.wxuserhb.service.impl.OWechatuserHongbaoServiceImpl;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.naming.NoNameCoder;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
import javax.net.ssl.SSLContext;
import java.io.*;
import java.security.KeyStore;
import java.text.SimpleDateFormat;
import java.util.*;
@Service
public class HongBaoUtil {
/**
* 现金红包
* @Title: bindDevice
* @return String
* @throws
*/
public Map<String, String> sendRedPack(@RequestBody WxRedpackSdkVo redPack) throws Exception{
redPack.setMch_id("商户号");
redPack.setClient_ip("服务端地址或设备地址(不大重要填自己服务器地址就行)");
redPack.setWxappid("appId");
redPack.setWishing("感谢您为环保做出的贡献");
redPack.setSend_name("随手拍服务平台");
redPack.setAct_name("随手拍举报奖励");
redPack.setRemark("保护环境人人有责,感谢您为环境保护贡献一份力量,希望您继续保持");
// 生成订单号
String billno = redPack.getMch_id()+ new SimpleDateFormat("yyyyMMddHHmmssSSS") .format(new Date() ) ;
String noncestr = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
redPack.setNonce_str(noncestr);
redPack.setMch_billno(billno);
// 微信现金红包Url 地址
String sendEedPackUrl = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";
// 生成签名
String sign = createSendRedPackOrderSign(redPack);
redPack.setSign(sign);
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);
}
}
};
}
});
xstream.alias("xml", redPack.getClass());
String xml = xstream.toXML(redPack);
String response = ssl(sendEedPackUrl,xml);
Map<String, String> mapstr = new HashMap<>();
Document doc = null;
try {
doc = DocumentHelper.parseText(response);
} catch (DocumentException e) {
e.printStackTrace();
}
Element root = doc.getRootElement();// 指向根节点
Iterator it = root.elementIterator();
while (it.hasNext()) {
Element element = (Element) it.next();// 一个Item节点
System.out.println(element.getName() + " : " + element.getTextTrim());
mapstr.put(element.getName(),element.getTextTrim());
}
return mapstr;
}
/**
* 生成签名
* @param redPack
* @return
*/
public String createSendRedPackOrderSign(WxRedpackSdkVo redPack){
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("xxxx生成签名用");
return DigestUtils.md5Hex(sign.toString()).toUpperCase();
}
/**
* 发送链接
* @param url
* @param data
* @return
*/
private String ssl(String url,String data){
StringBuffer message = new StringBuffer();
String mchId = "商户号";
try {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
FileInputStream instream = new FileInputStream(new File("/home/hb/apiclient_cert.p12")); // 证书位置
keyStore.load(instream, mchId.toCharArray());
SSLContext sslcontext = SSLContexts.custom()
.loadKeyMaterial(keyStore, mchId.toCharArray())
.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
new String[] { "TLSv1" },
null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
HttpPost httpost = new HttpPost(url);
httpost.addHeader("Connection", "keep-alive");
httpost.addHeader("Accept", "*/*");
httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
httpost.addHeader("Host", "api.mch.weixin.qq.com");
httpost.addHeader("X-Requested-With", "XMLHttpRequest");
httpost.addHeader("Cache-Control", "max-age=0");
httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
httpost.setEntity(new StringEntity(data, "UTF-8"));
System.out.println("executing request" + httpost.getRequestLine());
CloseableHttpResponse response = httpclient.execute(httpost);
try {
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(),"UTF-8"));
String text;
while ((text = bufferedReader.readLine()) != null) {
message.append(text);
}
}
EntityUtils.consume(entity);
} catch (IOException e) {
e.printStackTrace();
} finally {
response.close();
}
} catch (Exception e1) {
e1.printStackTrace();
}
return message.toString();
}
}
使用:
这个说明一下,不用按照下图所示,就是在你需要使用的地方无论是controller,还是serviceimpl中,把HongBaoUtil注册为一个service服务,然后把未赋值的参数提供一下,调用服务中的函数即可发送,返回的为map集合。
@Service
public class OWechatuserHongbaoServiceImpl implements IOWechatuserHongbaoService
{
@Autowired
private HongBaoUtil hongbaoService;
/**
* 发红包
* @param dto
* @return
*/
@Override
public void bufaHongbao() {
WxRedpackSdkVo wdto = new WxRedpackSdkVo();
wdto.setTotal_amount(100); // 设置金额,分为单位
wdto.setTotal_num(1); // 红包数量
wdto.setRe_openid("xxxxxx") // 用户该公众号下的openID;
Map<String, String> mapstr = null;
try {
mapstr = hongbaoService.sendRedPack(wdto);
} catch (Exception e) {
log.error("补发红包出错"+dto.toString());
e.printStackTrace();
}
System.out.println(mapstr);
}
}