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

一.p12证书下载

二.开发环境、参数准备
  • 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 {

    @Autowired
    SysUserService sysUserService;
    @Autowired
    AppUserService appUserService;
    @Autowired
    WithdrawalRecordService 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"; // 企业付款API

    private static final String TRANSFERS_PAY_QUERY = "https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo"; // 企业付款查询API

    private static final String APP_ID = "wx100000001000"  ;//公众账号appid

    private static final String MCH_ID = "14000000000";//商户号

    private static final String API_SECRET = "85565656565656565656565";//API密钥

    /**
     * 企业向个人支付转账
     * @param request
     * @param params
     */
    @PostMapping(value = "/pay")
    @ResponseBody
    @Transactional
    public 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");//用户id
        String openid = "";//用户openid
        Float applyMoney = jsonObject.getFloat("amount");//用户申请提现金额 0.3-5000
        int userType = jsonObject.getInteger("userType");//用户类型
        String amount;//企业付款金额
        Float poundage = 0f;//手续费
        String desc;//企业付款描述信息
        String id = UUID.randomUUID().toString().replaceAll("-", "");//提现记录表id

        if(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); //公众账号appid
            parm.put("mchid", MCH_ID); //商户号
            parm.put("nonce_str", PayUtil.getNonceStr()); //随机字符串
            parm.put("partner_trade_no", PayUtil.getTransferNo()); //商户订单号
            parm.put("openid", openid); //用户openid oCVr20N2YLH9VQztnkZTaCj2aYYY
            parm.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);//用户id
            map.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位数 00000001
		return "TNO" + DateUtil.formatDate(new Date(), DateUtil.TIME_STAMP_PATTERN) + "00000001";
	}

	/**
	 * 退款单号
	 * 
	 * @return
	 */
	public static String getRefundNo() {
		// 自增8位数 00000001
		return "RNO" + DateUtil.formatDate(new Date(), DateUtil.TIME_STAMP_PATTERN) + "00000001";
	}

	/**
	 * 退款单号
	 * 
	 * @return
	 */
	public static String getTransferNo() {
		// 自增8位数 00000001
		return "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才是真实ip
			int 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;
	}

}


  • 9
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 18
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值