本文共 16679 字,大约阅读时间需要 55 分钟。
有了微信支付 的开发做铺垫,相关的微信其他业务处理起来逻辑就能清晰很多。
准备好这两个架包
---------------------------------------------------------------------------------------------------1.微信公众号发红包 开发流程图----------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------2.红包实体-----------------------------------------------------------------------------------------------------
package net.shopxx.wx.redPackage;/** * 微信公众号 发红包实体 * @author SXD * */public class RedPack { /** * 随机字符串 * 随机字符串,不长于32位 */ private String nonce_str; /** * 签名 */ private String sign; /** * 商户订单号 * 商户订单号(每个订单号必须唯一。取值范围:0~9,a~z,A~Z)接口根据商户订单号支持重入,如出现超时可再调用。 */ private String mch_billno; /** * 商户号 * 微信支付分配的商户号 */ private String mch_id; /** * 公众账号 * 微信分配的公众账号ID(企业号corpid即为此appId) */ private String wxappid; /** * 商户名称 * 红包发送者名称 */ private String send_name; /** * 用户openid * 接受红包的用户 * 用户在wxappid下的openid */ private String re_openid; /** * 付款金额 单位:分 * 100 == 1元钱 ,也就是说 这里的 1 相当于1分钱 * 微信发送红包不少于1元钱 */ private int total_amount; /** * 红包发放总人数 */ private int total_num; /** * 红包祝福语 */ private String wishing; /** * Ip地址 * 调用接口的机器Ip地址 */ private String client_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; } }
-----------------------------------------------------------------------------------------------3.服务器端处理 逻辑---------------------------------------------------------------------------------------
package net.shopxx.wx.redPackage;import java.util.Map;import java.util.UUID;import javax.net.ssl.SSLSocketFactory;import javax.net.ssl.X509TrustManager;import javax.servlet.http.HttpServletRequest;import net.shopxx.wx.pay.HttpConnection;import net.shopxx.wx.pay.WeXinUtil;import net.shopxx.wx.pay.XmlUtil;import okhttp3.MediaType;import okhttp3.OkHttpClient;import okhttp3.Request;import okhttp3.RequestBody;import okhttp3.Response;import okhttp3.internal.platform.Platform;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;@Controller@RequestMapping("/wx/SendRedPack")public class SendRedPackController { /** * 公众账号ID */ @Value("${member.appid}") private String APPID; /** * 商户号 */ private String MCHID; /** * key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 */ private String KEY; private XmlUtil xmlUtil = new XmlUtil(); /** * ②接收请求 * @param request * @param open_id * @throws Exception */ @ResponseBody @RequestMapping("/sendRedPack") public void sendRedPack(HttpServletRequest request,String open_id) throws Exception{ RedPack pack = new RedPack(); pack.setAct_name("活动名称111"); pack.setClient_ip(WeXinUtil.getIp(request)); pack.setMch_billno("order_id"); pack.setMch_id(MCHID); String nonce = UUID.randomUUID().toString().replaceAll("-", ""); pack.setNonce_str(nonce); pack.setRe_openid(open_id); pack.setRemark("备注信息"); pack.setSend_name("商户名称:谁发的红包"); pack.setTotal_amount(1000); pack.setTotal_num(1); pack.setWishing("红包祝福语"); pack.setWxappid(APPID); String sign = WeXinUtil.createUnifiedOrderSign(pack,KEY); pack.setSign(sign); /** * 转成XML格式 微信可接受的格式 */ xmlUtil.getXstreamInclueUnderline().alias("xml", pack.getClass()); String xml = xmlUtil.getXstreamInclueUnderline().toXML(pack); //发起请求前准备 RequestBody body = RequestBody.create(MediaType.parse("text/xml;charset=UTF-8"), xml); Request req = new Request.Builder() .url("https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack") .post(body) .build(); //为http请求设置证书 SSLSocketFactory socketFactory = WeXinUtil.getSSL().getSocketFactory(); X509TrustManager x509TrustManager = Platform.get().trustManager(socketFactory); OkHttpClient okHttpClient = new OkHttpClient.Builder().sslSocketFactory(socketFactory, x509TrustManager).build(); //得到输出内容 /** *③ ④ 解析结果,判断是否红包发送成功 */ Response response = okHttpClient.newCall(req).execute(); String content = response.body().string(); MapresponseMap = xmlUtil.parseXML(content); if("SUCCESS".equals(responseMap.get("return_code"))){ System.out.println("红包发送成功"); System.out.println("签名"+responseMap.get("sign")+"业务结果"+responseMap.get("result_code")); if("SUCCESS".equals(responseMap.get("result_code"))){ System.out.println("商户订单号"+responseMap.get("mch_billno")+ "商户号"+responseMap.get("mch_id")+ "公众账号appid"+responseMap.get("wxappid")+ "用户openid"+responseMap.get("re_openid")+ "付款金额"+responseMap.get("total_amount")+ "微信单号"+responseMap.get("send_listid")); } }else{ System.out.println("红包发送失败"); } } }
-----------------------------------------------------------------------------------------------4.XML工具类--------------------------------------------------------------------------------------------------
package net.shopxx.wx.pay;import java.io.Writer;import java.util.HashMap;import java.util.List;import java.util.Map;import org.dom4j.Document;import org.dom4j.DocumentException;import org.dom4j.DocumentHelper;import org.dom4j.Element;import com.thoughtworks.xstream.XStream;import com.thoughtworks.xstream.core.util.QuickWriter;import com.thoughtworks.xstream.io.naming.NoNameCoder;import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;import com.thoughtworks.xstream.io.xml.XppDriver;/** * 微信支付 微信公众号发红包 * 封装/解析xml消息的工具类 * @author SXD * */public class XmlUtil { public XStream getXstreamInclueUnderline(){ XStream stream = new XStream(new XppDriver(new NoNameCoder()) { @Override public PrettyPrintWriter 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(""); } else { writer.write(text); } } }; } }); return stream; } /** * 根据字符串 解析XML map集合 * @param xml * @return * @throws DocumentException */ public MapparseXML(String xml) throws DocumentException{ Document document = DocumentHelper.parseText(xml); Element element =document.getRootElement(); List childElements = element.elements(); Map map = new HashMap (); map = getAllElements(childElements,map); map.forEach((k,v)->{ System.out.println(k+">>>>"+v); }); return map; } /** * 获取 子节点的被迭代方法 * @param childElements * @param mapEle * @return */ private Map getAllElements(List childElements,Map mapEle) { for (Element ele : childElements) { if(ele.elements().size()>0){ mapEle = getAllElements(ele.elements(), mapEle); }else{ mapEle.put(ele.getName(), ele.getText()); } } return mapEle; } }
-----------------------------------------------------------------------------------------------5.微信工具类---------------------------------------------------------------------------------------------------
package net.shopxx.wx.pay;import java.io.IOException;import java.io.InputStream;import java.lang.reflect.Field;import java.security.KeyManagementException;import java.security.KeyStore;import java.security.KeyStoreException;import java.security.NoSuchAlgorithmException;import java.security.UnrecoverableKeyException;import java.util.Comparator;import java.util.HashMap;import java.util.Map;import java.util.TreeMap;import javax.net.ssl.SSLContext;import javax.security.cert.CertificateException;import javax.servlet.http.HttpServletRequest;import org.apache.commons.codec.digest.DigestUtils;import org.apache.http.ssl.SSLContexts;import org.springframework.core.io.ClassPathResource;import org.springframework.core.io.Resource;/** * 微信支付 微信公众号发红包 * 工具类 * @author SXD * */public class WeXinUtil { /** * 获取用户IP * @param request * @return */ public static String getIp(HttpServletRequest request){ String ipAddress = null; if (request.getHeader("x-forwarded-for") == null) { ipAddress = request.getRemoteAddr(); }else{ if(request.getHeader("x-forwarded-for").length() > 15){ String [] aStr = request.getHeader("x-forwarded-for").split(","); ipAddress = aStr[0]; } else{ ipAddress = request.getHeader("x-forwarded-for"); } } return ipAddress; } /** * 签名算法,生成统一下单中 必填项签名 * @param unifiedOrder 1.将统一下单实体中各个字段拼接 2.MD5加密 3.全部转化为大写 * @return 返回经过签名算法生成的签名 sign * 第一步的规则 * ◆ 参数名ASCII码从小到大排序(字典序); * ◆ 如果参数的值为空不参与签名; * ◆ 参数名区分大小写; * ◆ 验证调用返回或微信主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。 * ◆ 微信接口可能增加字段,验证签名时必须支持增加的扩展字段 */ /* 手动拼接方式 public String createUnifiedOrderSign(Unifiedorder unifiedOrder){ StringBuffer sign = new StringBuffer(); sign.append("appid=").append(unifiedOrder.getAppid()); sign.append("&body=").append(unifiedOrder.getBody()); sign.append("&mch_id=").append(unifiedOrder.getMch_id()); sign.append("&nonce_str=").append(unifiedOrder.getNonce_str()); sign.append("¬ify_url=").append(unifiedOrder.getNotify_url()); sign.append("&openid=").append(unifiedOrder.getOpenid()); sign.append("&out_trade_no=").append(unifiedOrder.getOut_trade_no()); sign.append("&spbill_create_ip=").append(unifiedOrder.getSpbill_create_ip()); sign.append("&total_fee=").append(unifiedOrder.getTotal_fee()); sign.append("&trade_type=").append(unifiedOrder.getTrade_type()); sign.append("&key=").append(KEY); return DigestUtils.md5Hex(sign.toString()).toUpperCase(); } */ /** * 拼接生成sign 签名 * @param unifiedOrder * @param KEY * @return * @throws Exception */ public static String createUnifiedOrderSign(Object object,String KEY) throws Exception{ StringBuffer sign = new StringBuffer(); Mapmap = getSortMap(object); boolean isNotFirst = false; for (Map.Entry entry : map.entrySet()) { if(isNotFirst == true){ sign.append("&"); }else{ isNotFirst = true; } sign.append(entry.getKey()).append("=").append(entry.getValue()); } sign.append("&key=").append(KEY); return DigestUtils.md5Hex(sign.toString()).toUpperCase(); } /** * 使用java反射机制,动态获取对象的属性和参数值,排除值为null的情况,并按字典序排序 * @param object * @return * @throws Exception */ private static Map getSortMap(Object object) throws Exception{ Field[] fields = object.getClass().getDeclaredFields(); Map map = new HashMap (); for(Field field : fields){ String name = field.getName(); String methodName = "get" + name.replaceFirst(name.substring(0, 1), name.substring(0, 1) .toUpperCase()); // 调用getter方法获取属性值// Method getter = object.getClass().getMethod(methodName);// String value = getter.invoke(object)+""; field.setAccessible(true); Object value = field.get(object); if (value != null){ map.put(name, value.toString()); } } Map sortMap = new TreeMap ( new Comparator () { @Override public int compare(String arg0, String arg1) { return arg0.compareTo(arg1); } }); sortMap.putAll(map); return sortMap; } public static SSLContext getSSL() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException, java.security.cert.CertificateException { KeyStore keyStore = KeyStore.getInstance("PKCS12"); //证书位置 放在自己的项目下面 Resource resource = new ClassPathResource("apiclient_cert.p12"); InputStream instream = resource.getInputStream(); try { keyStore.load(instream, "填写证书密码,默认为商户号".toCharArray()); } finally { instream.close(); } SSLContext sslcontext = SSLContexts.custom() .loadKeyMaterial(keyStore, "填写证书密码,默认为商户号".toCharArray()) .build(); return sslcontext; } }
----------------------------------------------------------------------------------------------至此,微信公众号 发送红包 【待完善】---------------------------------------------------------------
转载地址:http://bnebm.baihongyu.com/