一.p12证书下载

  • 企业付款到零钱API (建议多看)
  • apiclient_cert.p12证书:在微信商户平台–>账户设置–>API安全–>证书中下载的 。 (自行下载)

二.开发环境、参数准备

  • SpringBoot2.0框架 (仅限本例,其他框架自行解决,原理相同)
  • APP_ID (公众账号appid)
  • MCH_ID(商户号)
  • API_SECRET(API密钥)

三.pom相关jar包、插件引入

1. xml相关jar包引入(微信接口要求以xml格式传参)

 <dependencies><!-- xml --><dependency><groupId>net.sf.kxml</groupId><artifactId>kxml2</artifactId><version>2.3.0</version></dependency><dependency><groupId>xmlpull</groupId><artifactId>xmlpull</artifactId><version>1.1.3.1</version></dependency></dependencies>

2. maven过滤证书插件引入

 <build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-resources-plugin</artifactId><version>2.7</version><configuration><encoding>UTF-8</encoding><!-- 过滤后缀为p12、crt的证书文件 --><nonFilteredFileExtensions><nonFilteredFileExtension>p12</nonFilteredFileExtension><nonFilteredFileExtension>crt</nonFilteredFileExtension></nonFilteredFileExtensions></configuration></plugin></plugins></build>

3. maven证书资源引入注意: 1.将下载好的证书放在src/main/resources下,2.按如下配置pom)

 <build><resources><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include><include>**/*.p12</include></includes><filtering>true</filtering></resource></resources></build>

四.代码实现

1. TransferController(提现相关接口)

package com.zero.jimu.controller;import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.util.StringUtil;
import com.zero.jimu.entity.WithdrawalRecord;
import com.zero.jimu.service.WithdrawalRecord.WithdrawalRecordService;
import com.zero.jimu.service.appUser.AppUserService;
import com.zero.jimu.service.sysUser.SysUserService;
import com.zero.jimu.utils.CheckParamsUtil;
import com.zero.jimu.utils.DateUtil;
import com.zero.jimu.utils.IpAddrUtil;
import com.zero.jimu.utils.exception.ErrorEnum;
import com.zero.jimu.utils.exception.Result;
import com.zero.jimu.utils.exception.ResultUtil;
import com.zero.jimu.utils.withdrawal.CollectionUtil;
import com.zero.jimu.utils.withdrawal.HttpUtils;
import com.zero.jimu.utils.withdrawal.PayUtil;
import com.zero.jimu.utils.withdrawal.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;/*** 提现相关接口*/
@RestController
@RequestMapping("/transfer")
public class TransferController {@AutowiredSysUserService sysUserService;@AutowiredAppUserService appUserService;@AutowiredWithdrawalRecordService withdrawalRecordService;private static final Logger logger = LoggerFactory.getLogger(TransferController.class);private static final String TRANSFERS_PAY = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"; // 企业付款APIprivate static final String TRANSFERS_PAY_QUERY = "https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo"; // 企业付款查询APIprivate static final String APP_ID = "wx100000001000"  ;//公众账号appidprivate static final String MCH_ID = "14000000000";//商户号private static final String API_SECRET = "85565656565656565656565";//API密钥/*** 企业向个人支付转账* @param request* @param params*/@PostMapping(value = "/pay")@ResponseBody@Transactionalpublic Result transferPay(@RequestBody String params,HttpServletRequest request) {/** =============================================接口参数校验================================================*/JSONObject jsonObject = JSONObject.parseObject(params);//解析json//校验参数是否为空if(CheckParamsUtil.isBlank(jsonObject,"userId","amount","userType")){return ResultUtil.fail(ErrorEnum.ERROR_PARAM_ISBLANK);}/**==============================================设置局部变量=================================================*/String userId = jsonObject.getString("userId");//用户idString openid = "";//用户openidFloat applyMoney = jsonObject.getFloat("amount");//用户申请提现金额 0.3-5000int userType = jsonObject.getInteger("userType");//用户类型String amount;//企业付款金额Float poundage = 0f;//手续费String desc;//企业付款描述信息String id = UUID.randomUUID().toString().replaceAll("-", "");//提现记录表idif(applyMoney<0.3||applyMoney>5000){return ResultUtil.fail("00000001","申请提现金额不符:低于最小金额0.30元或高于5000.00元");}/** ======================================业务判断 1.userId是否有收款资格=====================================*/if(userType == 1){openid = sysUserService.getOpenidBySysUserId(userId);}if(userType == 2){openid = appUserService.getOpenidByAppUserId(userId);}if(openid==null||openid.equals("")){return ResultUtil.fail("00000001","该用户不可提现");}/** ======================================业务判断 2.openid可提现金额校验=====================================*//** userType==1 商家身份*/if(userType == 1){//校验用户提现金额//1.提现金额<=可提现金额 15%的抽成}Float account = 0f;/** userType==2 用户身份*/if(userType == 2){//校验用户提现金额//1.提现金额<=可提现金额account = appUserService.getAccount(userId);if(applyMoney>account){return ResultUtil.fail("00000001","非法操作:申请提现金额大于可提现金额");}}/** =================================业务判断 3.userId当天提现次数及当天提现金额限制==================================*///当日提现次数 首次免手续费List<WithdrawalRecord> withdrawalRecords = withdrawalRecordService.selectWithdrawalRecordOfToday(userId,openid,userType);//当日非初次提现if(withdrawalRecords.size()>0&&withdrawalRecords.size()<=10){poundage = 2f;//当日非初次提现,手续费为2元desc = "申请提现金额:"+applyMoney+"元,当天已提现"+withdrawalRecords.size()+"次,需扣除2元手续费";//此处对用户当天累计提现金额可做限制
//            Float withdrawalAmountRequested = 0f;//用户今日累计已申请的提现额度
//            for(int i = 0;i < withdrawalRecords.size();i++){//                withdrawalAmountRequested = (withdrawalAmountRequested*1000+withdrawalRecords.get(i).getActualMoney()*1000)/1000;
//            }}else if(withdrawalRecords.size()>10){return ResultUtil.fail("00000001","该用户当天提现次数上限:微信企业付款每天最多可向同一个用户付款10次");}else{desc = "申请提现金额:"+applyMoney+"元,当天首次提现免手续费";}/** =================================业务判断 4.一个商户同一日付款总额限额10万元==================================*/Float amountWithdrawn = withdrawalRecordService.selectAllWithdrawalRecordNumOfToday();//商户同一日付款总额if(amountWithdrawn>100000){return ResultUtil.fail("00000001","今日商户付款总额限额,请明天再试");}/** ========================校验实际提现金额是否在微信企业付款实际允许的提现(0.3-5000)范围内=========================*/Float actualMoney = (applyMoney*1000-poundage*1000)/1000;//实际提现金额if(actualMoney<0.3||actualMoney>5000){return ResultUtil.fail("00000001","扣除手续费后的实际提现金额不符:"+actualMoney+"元:低于最小金额0.30元或高于5000.00元");}amount = Integer.parseInt((int)((actualMoney)*10)+"")*10+"";//微信企业付款金额 30-500000/** ==================================================================================================================*//** ==================================================封装提现所需参数================================================*//** ==================================================================================================================*/Map<String, String> restmap = null;try {Map<String, String> parm = new HashMap<String, String>();parm.put("mch_appid", APP_ID); //公众账号appidparm.put("mchid", MCH_ID); //商户号parm.put("nonce_str", PayUtil.getNonceStr()); //随机字符串parm.put("partner_trade_no", PayUtil.getTransferNo()); //商户订单号parm.put("openid", openid); //用户openid oCVr20N2YLH9VQztnkZTaCj2aYYYparm.put("check_name", "NO_CHECK"); //校验用户姓名选项 OPTION_CHECK//parm.put("re_user_name", "安迪"); //check_name设置为FORCE_CHECK或OPTION_CHECK,则必填parm.put("amount",amount); //转账金额parm.put("desc", desc); //企业付款描述信息parm.put("spbill_create_ip", IpAddrUtil.getIpAddr(request)); //Ip地址parm.put("sign", PayUtil.getSign(parm, API_SECRET));String restxml = HttpUtils.posts(TRANSFERS_PAY, XmlUtil.xmlFormat(parm, false));restmap = XmlUtil.xmlParse(restxml);} catch (Exception e) {logger.error(e.getMessage(), e);return ResultUtil.fail("00000001","转账发生异常");}/** ========================================================提现结果处理===================================================*//** ===================================================生成提现及流水记录,改变余额==================================================*/if (CollectionUtil.isNotEmpty(restmap) && "SUCCESS".equals(restmap.get("result_code"))) {logger.info("转账成功");Map<String, String> transferMap = new HashMap<>();transferMap.put("partnerTradeNo", restmap.get("partner_trade_no"));//商户转账订单号transferMap.put("paymentNo", restmap.get("payment_no")); //微信订单号transferMap.put("paymentTime", restmap.get("payment_time")); //微信支付成功时间//生成提现记录withdrawalRecordService.insert(new WithdrawalRecord(id,userType,userId,applyMoney,poundage,actualMoney,1,restmap.get("partner_trade_no"),restmap.get("payment_no"),restmap.get("payment_time")==null?null:DateUtil.strToDate(restmap.get("payment_time"),"yyyy-MM-dd HH:mm:ss"),openid,desc,restmap.get("spbill_create_ip"),"0"));//生成流水表String waterId = UUID.randomUUID().toString().replaceAll("-", "");Map<String,Object> map = new HashMap<>();map.put("id",waterId);//编号map.put("userId",userId);//用户idmap.put("title","提现");//该流水的标题map.put("waterType",2);//商家流水类型1.场地收入 2.提现    用户流水类型1.分销收入 2.提现 3.预订场地map.put("incomeExpense",1);//收入还是支出 0.收入 1.支出map.put("applyMoney",applyMoney);//申请提现金额map.put("poundage",poundage);//手续费map.put("actualMoney",actualMoney);//实际金额map.put("whetherToAccount",1);//是否到账0.未到账1.已到账if(userType==1){sysUserService.insertUserWater(map);//改变用户可提现余额}if(userType==2){appUserService.insertUserWater1(map);//改变用户可提现余额appUserService.updateUserAccount(userId,(account*1000-applyMoney*1000)/1000);//float精度问题}return ResultUtil.success(transferMap);}/** =================================================3.转账失败========================================================*/else {if (CollectionUtil.isNotEmpty(restmap)) {logger.info("转账失败:" + restmap.get("err_code") + ":" + restmap.get("err_code_des"));}return ResultUtil.fail("00000001","转账失败"+restmap.get("err_code_des"));}}/*** 企业向个人转账查询* @param request* @param response* @param tradeno 商户转账订单号* @param callback*/@PostMapping(value = "/pay/query")public Result orderPayQuery(HttpServletRequest request, HttpServletResponse response, String tradeno,String callback) {if (StringUtil.isEmpty(tradeno)) {return ResultUtil.fail("00000001","转账订单号不能为空");}Map<String, String> restmap = null;try {Map<String, String> parm = new HashMap<String, String>();parm.put("appid", APP_ID);parm.put("mch_id", MCH_ID);parm.put("partner_trade_no", tradeno);parm.put("nonce_str", PayUtil.getNonceStr());parm.put("sign", PayUtil.getSign(parm, API_SECRET));String restxml = HttpUtils.posts(TRANSFERS_PAY_QUERY, XmlUtil.xmlFormat(parm, true));restmap = XmlUtil.xmlParse(restxml);} catch (Exception e) {logger.error(e.getMessage(), e);}if (CollectionUtil.isNotEmpty(restmap) && "SUCCESS".equals(restmap.get("result_code"))) {// 订单查询成功 处理业务逻辑logger.info("订单查询:订单" + restmap.get("partner_trade_no") + "支付成功");Map<String, String> transferMap = new HashMap<>();transferMap.put("partnerTradeNo", restmap.get("partner_trade_no"));//商户转账订单号transferMap.put("openid", restmap.get("openid")); //收款微信号transferMap.put("paymentAmount", restmap.get("payment_amount")); //转账金额transferMap.put("transferTime", restmap.get("transfer_time")); //转账时间transferMap.put("desc", restmap.get("desc")); //转账描述return ResultUtil.success(transferMap);}else {if (CollectionUtil.isNotEmpty(restmap)) {logger.info("订单转账失败:" + restmap.get("err_code") + ":" + restmap.get("err_code_des"));}return ResultUtil.fail("00000001","订单转账失败");}}}

2. HttpUtils(企业付款http请求工具)

package com.zero.jimu.utils.withdrawal;import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
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.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;/*** 企业付款http请求工具*/
public class HttpUtils {private static final String DEFAULT_CHARSET = "UTF-8";private static final int CONNECT_TIME_OUT = 5000; //链接超时时间3秒private static final RequestConfig REQUEST_CONFIG = RequestConfig.custom().setConnectTimeout(CONNECT_TIME_OUT).build();private static SSLContext wx_ssl_context = null; //微信支付ssl证书private static final String MCH_ID  = "1000000000";//证书密码默认是商户号static{Resource resource = new ClassPathResource("apiclient_cert.p12");//该证书名字最好改为别人猜不到的try {KeyStore keystore = KeyStore.getInstance("PKCS12");char[] keyPassword = MCH_ID.toCharArray(); //证书密码keystore.load(resource.getInputStream(), keyPassword);wx_ssl_context = SSLContexts.custom().loadKeyMaterial(keystore, keyPassword).build();} catch (Exception e) {e.printStackTrace();}}/*** @description 功能描述: get 请求* @param url 请求地址* @param params 参数* @param headers headers参数* @return 请求失败返回null*/public static String get(String url, Map<String, String> params, Map<String, String> headers) {CloseableHttpClient httpClient = null;if (params != null && !params.isEmpty()) {StringBuffer param = new StringBuffer();boolean flag = true; // 是否开始for (Entry<String, String> entry : params.entrySet()) {if (flag) {param.append("?");flag = false;} else {param.append("&");}param.append(entry.getKey()).append("=");try {param.append(URLEncoder.encode(entry.getValue(), DEFAULT_CHARSET));} catch (UnsupportedEncodingException e) {//编码失败}}url += param.toString();}String body = null;CloseableHttpResponse response = null;try {httpClient = HttpClients.custom().setDefaultRequestConfig(REQUEST_CONFIG).build();HttpGet httpGet = new HttpGet(url);response = httpClient.execute(httpGet);body = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);} catch (Exception e) {e.printStackTrace();} finally {if (response != null) {try {response.close();} catch (IOException e) {e.printStackTrace();}}if (httpClient != null) {try {httpClient.close();} catch (IOException e) {e.printStackTrace();}}}return body;}/*** @description 功能描述: get 请求* @param url 请求地址* @return 请求失败返回null*/public static String get(String url) {return get(url, null);}/*** @description 功能描述: get 请求* @param url 请求地址* @param params 参数* @return 请求失败返回null*/public static String get(String url, Map<String, String> params) {return get(url, params, null);}/*** @description 功能描述: post 请求* @param url 请求地址* @param params 参数* @return 请求失败返回null*/public static String post(String url, Map<String, String> params) {CloseableHttpClient httpClient = null;HttpPost httpPost = new HttpPost(url);List<NameValuePair> nameValuePairs = new ArrayList<>();if (params != null && !params.isEmpty()) {for (Entry<String, String> entry : params.entrySet()) {nameValuePairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));}}String body = null;CloseableHttpResponse response = null;try {httpClient = HttpClients.custom().setDefaultRequestConfig(REQUEST_CONFIG).build();httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, DEFAULT_CHARSET));response = httpClient.execute(httpPost);body = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);} catch (Exception e) {e.printStackTrace();} finally {if (response != null) {try {response.close();} catch (IOException e) {e.printStackTrace();}}if (httpClient != null) {try {httpClient.close();} catch (IOException e) {e.printStackTrace();}}}return body;}/*** @description 功能描述: post 请求* @param url 请求地址* @param s 参数xml* @return 请求失败返回null*/public static String post(String url, String s) {CloseableHttpClient httpClient = null;HttpPost httpPost = new HttpPost(url);String body = null;CloseableHttpResponse response = null;try {httpClient = HttpClients.custom().setDefaultRequestConfig(REQUEST_CONFIG).build();httpPost.setEntity(new StringEntity(s, DEFAULT_CHARSET));response = httpClient.execute(httpPost);body = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);} catch (Exception e) {e.printStackTrace();} finally {if (response != null) {try {response.close();} catch (IOException e) {e.printStackTrace();}}if (httpClient != null) {try {httpClient.close();} catch (IOException e) {e.printStackTrace();}}}return body;}/*** @description 功能描述: post https请求,服务器双向证书验证* @param url 请求地址* @param params 参数* @return 请求失败返回null*/public static String posts(String url, Map<String, String> params) {CloseableHttpClient httpClient = null;HttpPost httpPost = new HttpPost(url);List<NameValuePair> nameValuePairs = new ArrayList<>();if (params != null && !params.isEmpty()) {for (Entry<String, String> entry : params.entrySet()) {nameValuePairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));}}String body = null;CloseableHttpResponse response = null;try {httpClient = HttpClients.custom().setDefaultRequestConfig(REQUEST_CONFIG).setSSLSocketFactory(getSSLConnectionSocket()).build();httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, DEFAULT_CHARSET));response = httpClient.execute(httpPost);body = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);} catch (Exception e) {e.printStackTrace();} finally {if (response != null) {try {response.close();} catch (IOException e) {e.printStackTrace();}}if (httpClient != null) {try {httpClient.close();} catch (IOException e) {e.printStackTrace();}}}return body;}/*** @description 功能描述: post https请求,服务器双向证书验证* @param url 请求地址* @param s 参数xml* @return 请求失败返回null*/public static String posts(String url, String s) {CloseableHttpClient httpClient = null;HttpPost httpPost = new HttpPost(url);String body = null;CloseableHttpResponse response = null;try {httpClient = HttpClients.custom().setDefaultRequestConfig(REQUEST_CONFIG).setSSLSocketFactory(getSSLConnectionSocket()).build();httpPost.setEntity(new StringEntity(s, DEFAULT_CHARSET));response = httpClient.execute(httpPost);body = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);} catch (Exception e) {e.printStackTrace();} finally {if (response != null) {try {response.close();} catch (IOException e) {e.printStackTrace();}}if (httpClient != null) {try {httpClient.close();} catch (IOException e) {e.printStackTrace();}}}return body;}//获取ssl connection链接private static SSLConnectionSocketFactory getSSLConnectionSocket() {return new SSLConnectionSocketFactory(wx_ssl_context, new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"}, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier());}
}

3. XmlUtil (xml、map转换工具)

package com.zero.jimu.utils.withdrawal;import com.github.pagehelper.util.StringUtil;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;/*** xml、map转换工具*/
public class XmlUtil {private static final String PREFIX_XML = "<xml>";private static final String SUFFIX_XML = "</xml>";private static final String PREFIX_CDATA = "<![CDATA[";private static final String SUFFIX_CDATA = "]]>";/*** 转化成xml, 单层无嵌套* * @param parm* @param isAddCDATA* @return*/public static String xmlFormat(Map<String, String> parm, boolean isAddCDATA) {StringBuffer strbuff = new StringBuffer(PREFIX_XML);if (CollectionUtil.isNotEmpty(parm)) {for (Entry<String, String> entry : parm.entrySet()) {strbuff.append("<").append(entry.getKey()).append(">");if (isAddCDATA) {strbuff.append(PREFIX_CDATA);if (StringUtil.isNotEmpty(entry.getValue())) {strbuff.append(entry.getValue());}strbuff.append(SUFFIX_CDATA);} else {if (StringUtil.isNotEmpty(entry.getValue())) {strbuff.append(entry.getValue());}}strbuff.append("</").append(entry.getKey()).append(">");}}return strbuff.append(SUFFIX_XML).toString();}/*** 解析xml* * @param xml* @return* @throws XmlPullParserException* @throws IOException*/public static Map<String, String> xmlParse(String xml) throws XmlPullParserException, IOException {Map<String, String> map = null;if (StringUtil.isNotEmpty(xml)) {InputStream inputStream = new ByteArrayInputStream(xml.getBytes());XmlPullParser pullParser = XmlPullParserFactory.newInstance().newPullParser();pullParser.setInput(inputStream, "UTF-8"); // 为xml设置要解析的xml数据int eventType = pullParser.getEventType();while (eventType != XmlPullParser.END_DOCUMENT) {switch (eventType) {case XmlPullParser.START_DOCUMENT:map = new HashMap<String, String>();break;case XmlPullParser.START_TAG:String key = pullParser.getName();if (key.equals("xml"))break;String value = pullParser.nextText().trim();map.put(key, value);break;case XmlPullParser.END_TAG:break;}eventType = pullParser.next();}}return map;}
}

4. PayUtil

package com.zero.jimu.utils.withdrawal;import com.github.pagehelper.util.StringUtil;
import com.zero.jimu.utils.ChineseCharToEnUtil;
import com.zero.jimu.utils.DateUtil;
import com.zero.jimu.utils.Encrypt;import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.Set;public class PayUtil {/*** 生成订单号* * @return*/public static String getTradeNo() {// 自增8位数 00000001return "TNO" + DateUtil.formatDate(new Date(), DateUtil.TIME_STAMP_PATTERN) + "00000001";}/*** 退款单号* * @return*/public static String getRefundNo() {// 自增8位数 00000001return "RNO" + DateUtil.formatDate(new Date(), DateUtil.TIME_STAMP_PATTERN) + "00000001";}/*** 退款单号* * @return*/public static String getTransferNo() {// 自增8位数 00000001return "TNO" + DateUtil.formatDate(new Date(), DateUtil.TIME_STAMP_PATTERN) + "00000001";}/*** 返回客户端ip* * @param request* @return*/public static String getRemoteAddrIp(HttpServletRequest request) {String ip = request.getHeader("X-Forwarded-For");if (StringUtil.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {// 多次反向代理后会有多个ip值,第一个ip才是真实ipint index = ip.indexOf(",");if (index != -1) {return ip.substring(0, index);} else {return ip;}}ip = request.getHeader("X-Real-IP");if (StringUtil.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {return ip;}return request.getRemoteAddr();}/*** 获取服务器的ip地址* * @param request* @return*/public static String getLocalIp(HttpServletRequest request) {return request.getLocalAddr();}public static String getSign(Map<String, String> params, String paternerKey) throws UnsupportedEncodingException {return Encrypt.getMD5(createSign(params, false) + "&key=" + paternerKey).toUpperCase();}/*** 构造签名* * @param params* @param encode* @return* @throws UnsupportedEncodingException*/public static String createSign(Map<String, String> params, boolean encode) throws UnsupportedEncodingException {Set<String> keysSet = params.keySet();Object[] keys = keysSet.toArray();Arrays.sort(keys);StringBuffer temp = new StringBuffer();boolean first = true;for (Object key : keys) {if (key == null || StringUtil.isEmpty(params.get(key))) // 参数为空不参与签名continue;if (first) {first = false;} else {temp.append("&");}temp.append(key).append("=");Object value = params.get(key);String valueStr = "";if (null != value) {valueStr = value.toString();}if (encode) {temp.append(URLEncoder.encode(valueStr, "UTF-8"));} else {temp.append(valueStr);}}return temp.toString();}/*** 创建支付随机字符串* @return*/public static String getNonceStr(){return ChineseCharToEnUtil.randomString(ChineseCharToEnUtil.LETTER_NUMBER_CHAR, 32);}/*** 支付时间戳* @return*/public static String payTimestamp() {return Long.toString(System.currentTimeMillis() / 1000);}
}

5. CollectionUtil

package com.zero.jimu.utils.withdrawal;import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;/*** 集合类工具*/
public class CollectionUtil {private CollectionUtil() {super();}// 判断一个集合是否为空public static <T> boolean isEmpty(Collection<T> col) {if (col == null || col.isEmpty()) {return true;}return false;}// 判断一个集合是否不为空public static <T> boolean isNotEmpty(Collection<T> col) {return !isEmpty(col);}// 判断Map是否为空public static <K, V> boolean isEmpty(Map<K, V> map) {if (map == null || map.isEmpty()) {return true;}return false;}// 判断Map是否不为空为空public static <K, V> boolean isNotEmpty(Map<K, V> map) {return !isEmpty(map);}// 去除list中的重复数据public static <T> List<T> removeRepeat(List<T> list) {if (isEmpty(list)) {return list;}List<T> result = new ArrayList<T>();for (T e : list) {if (!result.contains(e)) {result.add(e);}}return result;}// 将集合转换为String数组public static <T> String[] toArray(List<T> list) {if (isEmpty(list)) {return null;}String[] result = new String[list.size()];for (int i = 0; i < list.size(); i++) {result[i] = String.valueOf(list.get(i));}return result;}}

微信提现——企业付款到零钱demo(超详细小白都看得懂的)相关推荐

  1. 微信支付-企业付款到零钱问题集锦

    前言 做拉新活动的奖金分发,商品售卖的分销体系.给与用户奖金 1. 需要证书 <xml> <return_code><![CDATA[SUCCESS]]></ ...

  2. 微信支付企业付款到零钱

    萌新第一次写博客,希望大佬们多多支持,以下是借鉴大佬的代码自己封装的一个方法. //企业付款到零钱public Result returnWechatMoney(HttpServletRequest ...

  3. 微信支付----企业付款到零钱和银行卡规则

    企业付款到零钱 微信官方文档:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_1 使用条件 1.商户号(或同主体 ...

  4. JAVA对接支付宝支付(超详细,一看就懂)

    Java对接支付宝支付 更多内容 冷文博客: 传送门 引入 为什么要发这篇帖子呢?原因很简单,就是因为在一个稍稍正规一点的应用上都会有支付这个环节,我们日常的在线支付如今包括支付宝,微信钱包,QQ钱包 ...

  5. thinkphp - 超详细实现私信功能,tp全版本通用的用户之间私信功能详细教程,从 “数据库设计“ → “控制器“ 开发(从 0-1 详细实现私信的教程,注释详细小白一看就懂,附带前端视图代码!)

    介绍 本博客基于 Thinkphp 框架,详细讲解了如何实现私信功能的设计,从数据库表设计再到控制器开发,并提供界面视图进行测试! 你可以直接复制控制器代码,快速将功能移植到你的项目中去. 数据库设计 ...

  6. 微信零钱数据在服务器,关于微信企业付款到零钱X509Certificate2读取证书信息,发布到服务器访问不到的解决方案...

    前言: 最近做了一个通过调用微信企业付款到用户零钱的功能,真的挺奇怪的,在我本地调试的时候都没有问题,但是当我发布到服务上的时候却一直无法读取到我的证书信息.读取的代码如下,使用的是微信官方文档提供的 ...

  7. PHP微信商户支付 - 企业付款到零钱功能(即提现)技术资料汇总

    PHP实现微信开发中提现功能(企业付款到用户零钱) 一.实现该功能目的 这几天在小程序里要实现用户从系统中提现到零钱的功能,查了一下文档可以使用 企业付款到用户零钱 来实现: 官方文档:https:/ ...

  8. asp源码demo下载:微信公众号支付企业付款到零钱功能asp源码下载案例

    最近接到一个开发需求,一个企业想用微信支付里面的,企业付款到零钱功能,利用此功能来给用会发红包,因为微信支付里的红包功能一次要付款1块钱,太多,所以他想利用此功能来发红包,这样红包金额可以低到每次3角 ...

  9. 微信支付、微信企业付款到零钱工具类

    微信支付.微信企业付款到零钱工具类 主要依赖:apache httpclient 4.5 jdk1.8 工具类主要功能: xml参数拼接 签名算法实现 post加密请求 import lombok.e ...

最新文章

  1. python unicode编码转换中文_python unicode转中文及转换默认编码
  2. 脚手架koa2+mockjs
  3. Python 简单入门指北(二)
  4. docker omv 防火墙_OpenMediaVault(OMV)配置Docker
  5. Mysql学习笔记【一、环境安装配置】
  6. 点击连接后不刷新就不显示页面的bug修复
  7. 求变量的数据类型,typeid,bool,C和C++的不同,new和delete,C++中的枚举,inline和可变参数模板,auto和函数模板,宽字符
  8. Python设置网卡自己封装的Internet类 WMI
  9. 2DASL:目前最好的开源人脸3D重建与密集对齐算法
  10. mysql sql 时间比较_mysql中sql语句进行日期比较
  11. git21天打卡-day5 day6 day7
  12. 自定义OutputFormat案例实操
  13. 软件安装管家软件目录
  14. 集线器、交换机、路由器以及端口带宽区别
  15. UE5 C++ Rider 编程指南 1.编辑器基础
  16. 1253 Dungeon Master
  17. 关于对接海康威视综合安防平台并使用SDK下载过车视频
  18. SystemviewV3.12移到目标板
  19. java密码复杂度匹配规则
  20. Remove.bg api 自动去背景 实例

热门文章

  1. Doxygen安装和使用
  2. 一种简单的贝塞尔插值算法
  3. 使用scikit-image feature计算图像特征与常见特征示例
  4. 中国软件10大最具影响力人物
  5. 基于webmagic的种子网站爬取
  6. C语言sin()函数绘制正弦曲线代码(0-2π)
  7. 高等教育心理学:知识的学习
  8. 揭秘卫星互联网!6G关键技术,国内行业雏形初现
  9. python绘制蚊香形_python之turtle画蚊香
  10. Window安全策略的制定与实施