1.首先查看官方文档查看url和请求参数,返回参数 pay.weixin.qq.com/wiki/doc/ap…
2.需要的前置条件
需要做的准备工作
1.下载API证书 商户平台->账号中心->API安全 下载API证书
查看配置使用说明
里面有什么语言使用什么证书,以及证书怎么使用的
2.充值
3.获取openid 目前支持向指定微信用户的openid发放指定金额红包。(获取openid参见微信公众平台开发者文档:网页授权获取用户基本信息)
4.相关参数设置
和红包相关的参数,你可以在页面上自主设置和更改。操作路径如下:【登录商户平台——>产品中心——>现金红包——>产品设置】(注:“产品设置”操作按钮仅当你开通现金红包功能之后才会出现)。还可以对额度及安全等参数进行设置;(特别注意:调用IP地址设置)
3.具体实现
1.在application.properties中配置所需要的参数
2.从配置文件获取参数及配置其他参数 WxAuthorization
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class WxAuthorization {
/**
* 微信公众号的AppId
*/
@Value("${wechat.appId}")
public String WX_APP_ID;
/**
* 应用授权作用域
*/
@Value("${wechat.scope}")
public String SCOPE;
/**
* 公众号的appSecret
*/
@Value("${wechat.secret}")
public String SECRET;
/**
* 微信支付分配的商户号
*/
@Value("${wechat.mchId}")
public String MCH_ID;
/**
* 商户名称
*/
@Value("商户名称")
public String SEND_NAME;
/**
* 付款金额
*/
@Value("${wechat.totalAmount}")
public String TOTAL_AMOUNT;
/**
* 红包发放总人数
*/
@Value("${wechat.totalNum}")
public int TOTAL_NUM;
/**
* 红包祝福语
*/
@Value("感谢您的参与")
public String WISHING;
/**
* Ip地址
*/
@Value("${wechat.clientIp}")
public String CLIENT_IP;
/**
* 活动名称
*/
@Value("活动名称")
public String ACT_NAME;
/**
* 备注
*/
@Value("备注")
public String REMARK;
/**
* 微信商户证书路径
*/
@Value("${wechat.certPath}")
public String CERT_PATH;
/**
* 商户平台设置的密钥key
*/
@Value("${wechat.key}")
public String KEY;
/**
* 商户平台设置的密钥key
*/
@Value("${wechat.url}")
public String URL;
}
3.主文件WxAuthorizedLogin 底下是主文件下的几个方法
openId通过授权获取的
/**
* 现金红包
* @Title: bindDevice
* @return String
* @throws
*/
public Map<String, String> sendRedPackUrl(String openId) {
SendRedPack sendRedPackOrderSign = createSendRedPackOrderSign(openId);
String xml = getXml(sendRedPackOrderSign);
log.info(xml);
String response = ssl(xml);
Map<String, String> responseMap = new HashMap<>();
try {
responseMap = xmlUtil.parseXml(response);
} catch (Exception e) {
log.error(e.toString());
}
return responseMap;
}
/**
* 证书使用及调红包接口发红包返回数据
* @param data
* @return
*/
private String ssl(String data){
StringBuffer message = new StringBuffer();
try {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
FileInputStream fileInputStream = new FileInputStream(new File(wxAuthorization.CERT_PATH));
keyStore.load(fileInputStream, wxAuthorization.MCH_ID.toCharArray());
// Trust own CA and all self-signed certs
SSLContext sslcontext = SSLContexts.custom()
.loadKeyMaterial(keyStore, wxAuthorization.MCH_ID.toCharArray())
.build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
sslcontext,
new String[] { "TLSv1" },
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sslConnectionSocketFactory)
.build();
HttpPost httpPost = new HttpPost(wxAuthorization.URL);
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.setEntity(new StringEntity(data, "UTF-8"));
log.info("executing request" + httpPost.getRequestLine());
CloseableHttpResponse response = httpclient.execute(httpPost);
try {
HttpEntity entity = response.getEntity();
log.info("" + response.getStatusLine());
if (entity != null) {
log.info("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();
}
log.info(message.toString());
return message.toString();
}
/**
* 随机字符串生成
* @return
*/
private static String getNonce_str()
{
String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 32; i++ )
{
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
/**
* 随机获取某一设置的红包金额
* @param totalAmount
* @return
*/
private int getAmount(String totalAmount) {
String[] amounts = totalAmount.split(",");
String amount = amounts[(int)(Math.random() * amounts.length)];
return Integer.parseInt(amount);
}
/**
* 签名生成和红包参数model封装
* @param openId
* @return
*/
private SendRedPack createSendRedPackOrderSign(String openId){
SendRedPack sendRedPack = SendRedPack.builder()
.act_name(wxAuthorization.ACT_NAME)
.client_ip(wxAuthorization.CLIENT_IP)
.mch_billno(wxAuthorization.MCH_ID
+ new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())
+ (int)((Math.random() * 9 + 1) * 1000))
.mch_id(wxAuthorization.MCH_ID)
.nonce_str(getNonce_str())
.re_openid(openId)
.remark(wxAuthorization.REMARK)
.send_name(wxAuthorization.SEND_NAME)
.total_amount(getAmount(wxAuthorization.TOTAL_AMOUNT))
.total_num(wxAuthorization.TOTAL_NUM)
.wishing(wxAuthorization.WISHING)
.wxappid(wxAuthorization.WX_APP_ID)
.build();
StringBuffer sign = new StringBuffer();
sign.append("act_name=").append(sendRedPack.getAct_name());
sign.append("&client_ip=").append(sendRedPack.getClient_ip());
sign.append("&mch_billno=").append(sendRedPack.getMch_billno());
sign.append("&mch_id=").append(sendRedPack.getMch_id());
sign.append("&nonce_str=").append(sendRedPack.getNonce_str());
sign.append("&re_openid=").append(sendRedPack.getRe_openid());
sign.append("&remark=").append(sendRedPack.getRemark());
sign.append("&send_name=").append(sendRedPack.getSend_name());
sign.append("&total_amount=").append(sendRedPack.getTotal_amount());
sign.append("&total_num=").append(sendRedPack.getTotal_num());
sign.append("&wishing=").append(sendRedPack.getWishing());
sign.append("&wxappid=").append(sendRedPack.getWxappid());
sign.append("&key=").append(wxAuthorization.KEY);
String s = DigestUtils.md5Hex(sign.toString()).toUpperCase();
sendRedPack.setSign(s);
return sendRedPack;
}
/**
* 红包功能接口参数xml封装
* @param sendRedPack
* @return
*/
public String getXml(SendRedPack sendRedPack) {
StringBuilder reqXmlStr = new StringBuilder();
reqXmlStr.append("<xml>");
reqXmlStr.append("<nonce_str><![CDATA[" + sendRedPack.getNonce_str() + "]]></nonce_str>");
reqXmlStr.append("<sign><![CDATA[" + sendRedPack.getSign() + "]]></sign>");
reqXmlStr.append("<mch_billno><![CDATA[" + sendRedPack.getMch_billno() + "]]></mch_billno>");
reqXmlStr.append("<mch_id><![CDATA[" + sendRedPack.getMch_id() + "]]></mch_id>");
reqXmlStr.append("<wxappid><![CDATA[" + sendRedPack.getWxappid() + "]]></wxappid>");
reqXmlStr.append("<send_name><![CDATA[" + sendRedPack.getSend_name() + "]]></send_name>");
reqXmlStr.append("<re_openid><![CDATA[" + sendRedPack.getRe_openid() + "]]></re_openid>");
reqXmlStr.append("<total_amount><![CDATA[" + sendRedPack.getTotal_amount() + "]]></total_amount>");
reqXmlStr.append("<total_num><![CDATA[" + sendRedPack.getTotal_num() + "]]></total_num>");
reqXmlStr.append("<wishing><![CDATA[" + sendRedPack.getWishing() + "]]></wishing>");
reqXmlStr.append("<client_ip><![CDATA[" + sendRedPack.getClient_ip() + "]]></client_ip>");
reqXmlStr.append("<act_name><![CDATA[" + sendRedPack.getAct_name() + "]]></act_name>");
reqXmlStr.append("<remark><![CDATA[" + sendRedPack.getRemark() + "]]></remark>");
reqXmlStr.append("</xml>");
return reqXmlStr.toString();
}
在提供两个我写的授权方法(code是通过前端传入的)
/**
* 通过code获取微信用户基本信息(授权)
* @param code
* @return
* @throws IOException
*/
public Result<WxUser> getWxUser(String code) {
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + wxAuthorization.WX_APP_ID + "&secret=" + wxAuthorization.SECRET + "&code=" + code + "&grant_type=authorization_code";
String s = doGet(url);
int index = s.indexOf("access_token");
if(index == -1) {
log.info("此code已经被使用");
return Result.error("此code已经被使用");
}
WxAccessToken token = JSON.parseObject(s, WxAccessToken.class);
String refreshUrl = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=" + wxAuthorization.WX_APP_ID + "&grant_type=refresh_token&refresh_token=" + token.getRefreshToken();
String s1 = doGet(refreshUrl);
WxAccessToken token1 = JSON.parseObject(s1, WxAccessToken.class);
String userUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + token1.getAccessToken() + "&openid=" + token1.getOpenId() + "&lang=zh_CN";
String s2 = doGet(userUrl);
log.info("微信返回参数:"+s2);
index = s2.indexOf("nickname");
if(index == -1) {
log.info("AppID无效");
return Result.error("AppID无效");
}
WxUser wxUser = JSON.parseObject(s2, WxUser.class);
return Result.ok(wxUser);
}
/**
* 通过code获取微信用户openid(静默授权)
* @param code
* @return
*/
public Result<String> getOpenId(String code) {
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + wxAuthorization.WX_APP_ID + "&secret=" + wxAuthorization.SECRET + "&code=" + code + "&grant_type=authorization_code ";
String s = doGet(url);
int index = s.indexOf("access_token");
if(index == -1) {
return Result.error("此code已经被使用");
}
WxAccessToken token = JSON.parseObject(s, WxAccessToken.class);
return Result.ok(token.getOpenId());
}
最后,还有一个xml的工具类XmlUtil
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.DomDriver;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
import com.thoughtworks.xstream.io.xml.XppDriver;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.stereotype.Component;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 解析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;
}
}
发送红包功能就全部结束了,调用sendRedPackUrl方法即可发送红包