123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- package com.llisoft.pay.service;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.UUID;
- import org.apache.commons.codec.digest.DigestUtils;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.stereotype.Service;
- import com.llisoft.common.util.DecimalUtil;
- import com.llisoft.common.util.HttpUtil;
- import com.llisoft.common.util.JsonUtil;
- import com.llisoft.common.util.XmlUtil;
- /**
- * 微信支付
- */
- @Service
- public class WxPayService {
-
- private Logger logger = LoggerFactory.getLogger(WxPayService.class);
-
- /** 微信接口 统一下单 */
- public static final String WX_API_ORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";
- /** 微信接口 查询订单 */
- public static final String WX_API_ORDERQUERY = "https://api.mch.weixin.qq.com/pay/orderquery";
-
- @Value("${mta.domain}")
- private String domain;
- @Value("${wxpay.mchid}")
- private String mchid;
- @Value("${wxpay.mchkey}")
- private String mchkey;
- @Value("${wxpay.appid}")
- private String appid;
- @Value("${wxpay.secret}")
- private String secret;
-
- @Autowired
- private PayService payService;
-
-
- /**
- * 支付
- * @param paynum
- * @param money
- * @param body
- * @return
- */
- public String pay(String paynum, int money, String body) {
- Map<String, String> paramMap = new HashMap<String ,String>();
- paramMap.put("appid", appid); // 公众账号ID
- paramMap.put("mch_id", mchid); // 商户号
- paramMap.put("nonce_str", getNonceStr()); // 随机字符串
- paramMap.put("out_trade_no", paynum); // 商户订单号
- paramMap.put("body", body); // 商品描述
- paramMap.put("total_fee", String.valueOf(money)); // 支付金额, 单位为【分】
- paramMap.put("spbill_create_ip", "127.0.0.1"); // 终端IP, APP和网页支付提交用户端ip
- paramMap.put("notify_url", domain+"/wxpay/notify"); // 通知地址
- paramMap.put("trade_type", "NATIVE"); // 交易类型, 取值如下:JSAPI,NATIVE,APP
- paramMap.put("sign", getSign(paramMap)); // 签名
- String xmlParamString = mapToXml(paramMap); // 封装xml格式参数字符串
- logger.info("微信统一下单api请求参数: {}", xmlParamString);
- String result = HttpUtil.postXml(WX_API_ORDER, xmlParamString);
- logger.info("微信统一下单api返回结果: {}", result);
- HashMap<String, String> resultMap = XmlUtil.toObject(result, HashMap.class, String.class, String.class);
- if ("SUCCESS".equals(resultMap.get("return_code"))) {
- return resultMap.get("code_url");
- }
- logger.error("微信统一下单api调用失败: {}", resultMap);
- return null;
- }
-
- /**
- * 支付 移动端
- * @param paynum
- * @param money
- * @param body
- * @return
- */
- public JsApiPayConfig paym(String paynum, int money, String body, String openid) throws Exception {
- Map<String, String> paramMap = new HashMap<String ,String>();
- paramMap.put("appid", appid); // 公众账号ID
- paramMap.put("mch_id", mchid); // 商户号
- paramMap.put("nonce_str", getNonceStr()); // 随机字符串
- paramMap.put("out_trade_no", paynum); // 商户订单号
- paramMap.put("body", body); // 商品描述
- paramMap.put("total_fee", String.valueOf(money)); // 支付金额, 单位为【分】
- paramMap.put("spbill_create_ip", "127.0.0.1"); // 终端IP, APP和网页支付提交用户端ip
- paramMap.put("notify_url", domain+"/wxpay/notify"); // 通知地址
- paramMap.put("trade_type", "JSAPI"); // 交易类型, 取值如下:JSAPI,NATIVE,APP
- paramMap.put("openid", openid); // 用户标识, trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。
- paramMap.put("sign", getSign(paramMap)); // 签名
- String xmlParamString = mapToXml(paramMap); // 封装xml格式参数字符串
- logger.info("微信统一下单api请求参数: {}", xmlParamString);
- String result = HttpUtil.postXml(WX_API_ORDER, xmlParamString);
- logger.info("微信统一下单api返回结果: {}", result);
- HashMap<String, String> resultMap = XmlUtil.toObject(result, HashMap.class, String.class, String.class);
- if ("SUCCESS".equals(resultMap.get("return_code"))) {
- String prepayid = resultMap.get("prepay_id");
- if (prepayid!=null && !prepayid.trim().isEmpty()) {
- // 微信js支付参数
- paramMap = new HashMap<String, String>();
- paramMap.put("appId", appid);
- paramMap.put("nonceStr", getNonceStr());
- paramMap.put("timeStamp", getTimeStamp());
- paramMap.put("package", "prepay_id=" + prepayid);
- paramMap.put("signType", "MD5");
- paramMap.put("paySign", getSign(paramMap));
- paramMap.put("packageStr", paramMap.get("package")); // 解决java中package关键字问题
- JsApiPayConfig jsApiPayConfig = JsonUtil.toObject(JsonUtil.toJson(paramMap), JsApiPayConfig.class);
- // 微信jsapi初始化参数 // TODO 未完待续,需要集成微信公众号网页授权
- // String result = HttpUtil.get(authurl + "/jsapi/config");
- // logger.info("调用微信授权服务: 获取jsapi初始化参数: {}", result);
- // jsApiPayConfig.setInitConfig(JsonUtil.toObject(result, JsApiConfig.class));
- // logger.info("返回微信js支付需要的参数信息: {}", JsonUtil.toJson(jsApiPayConfig));
- return jsApiPayConfig;
- }
- }
- logger.error("微信统一下单api调用失败: {}", resultMap);
- return null;
- }
-
- /**
- * 查询
- * @param paynum
- * @return
- */
- public Map<String, String> query(String paynum) {
- Map<String, String> paramMap = new HashMap<String ,String>();
- paramMap.put("appid", appid); // 公众账号ID
- paramMap.put("mch_id", mchid); // 商户号
- paramMap.put("nonce_str", getNonceStr()); // 随机字符串
- paramMap.put("out_trade_no", paynum); // 商户订单号
- paramMap.put("sign", getSign(paramMap)); // 签名
- // 封装xml格式参数字符串
- String xmlParamString = mapToXml(paramMap);
- logger.info("微信订单查询api请求参数: {}", xmlParamString);
- String result = HttpUtil.postXml(WX_API_ORDERQUERY, xmlParamString);
- logger.info("微信订单查询api返回结果: {}", result);
- Map<String, String> resultMap = XmlUtil.toObject(result, HashMap.class, String.class, String.class);
- return resultMap;
- }
-
- /**
- * 处理微信支付返回结果
- * @param resultMap
- * @return
- * @author YangJie
- * @throws Exception
- * @throws Throwable
- * @createTime 2015年3月31日 下午5:36:27
- */
- public boolean dispose(Map<String, String> resultMap) throws Exception {
- // 判断通信标识
- if (!"SUCCESS".equals(resultMap.get("return_code"))) {
- logger.error("微信支付处理: 通信标识异常: {}", resultMap.get("return_code"));
- return false;
- }
- // 验证签名
- if (!getSign(resultMap).equals(resultMap.get("sign"))) {
- logger.error("微信支付处理: 签名验证失败: {}", resultMap.get("sign"));
- return false;
- }
- // 判断交易状态
- if (!"SUCCESS".equals(resultMap.get("result_code"))) {
- logger.error("微信支付处理: 交易状态异常: {}", resultMap.get("result_code"));
- return false;
- }
- // 完成支付状态
- String paynum = resultMap.get("out_trade_no"); // paynum
- String tradenum = resultMap.get("trade_no"); // 支付宝交易号
- int totalAmount = DecimalUtil.toInt(resultMap.get("total_amount")); // 实际支付金额
- return payService.finish(paynum, tradenum, totalAmount, PayService.FLAG_NOTIFY);
- }
-
-
- /**
- * 获取随机字符串
- * @return 32字符以内
- * @author YangJie
- * @createTime 2015年3月26日 下午5:12:47
- */
- private String getNonceStr(){
- return UUID.randomUUID().toString().replace("-", "");
- }
-
- /**
- * 获取时间戳
- * @return 精确到秒
- * @author YangJie
- * @createTime 2015年3月26日 下午5:12:47
- */
- private String getTimeStamp(){
- return String.valueOf(System.currentTimeMillis()/1000);
- }
-
- /**
- * 获取微信认证签名(md5)
- * @param paramMap
- * @author YangJie
- * @createTime 2015年3月26日 下午2:48:17
- */
- private String getSign(Map<String, String> paramMap) {
- List<String> keyList = new ArrayList<String>(paramMap.keySet()); // 获取参数key
- Collections.sort(keyList); // key 排序
- StringBuffer paramBuffer = new StringBuffer();
- String value = null;
- for (String key : keyList) { // 循环封装非空参数
- value = paramMap.get(key);
- if (key != null && !key.equals("sign") && value!=null && !value.isEmpty()) {
- paramBuffer.append(key).append("=").append(value).append("&");
- }
- } // 添加私钥
- paramBuffer.append("key=").append(mchkey);
- return DigestUtils.md5Hex(paramBuffer.toString()).toUpperCase();
- }
-
- /**
- * 获取xml格式参数字符串
- * @param paramMap
- * @return
- * @author YangJie
- * @createTime 2015年3月26日 下午3:06:26
- */
- private String mapToXml(Map<String, String> paramMap) {
- StringBuilder xmlBuilder = new StringBuilder("<xml>");
- for (String key : paramMap.keySet()) {
- if (key != null && paramMap.get(key)!=null && !paramMap.get(key).isEmpty()) {
- xmlBuilder.append("<").append(key).append(">").append(paramMap.get(key))
- .append("</").append(key).append(">");
- }
- }
- xmlBuilder.append("</xml>");
- return xmlBuilder.toString();
- }
-
- /**
- * 微信js api 初始化参数
- */
- public class JsApiConfig{
- private String appId;
- private String timestamp;
- private String nonceStr;
- private String signature;
-
- public String getAppId() {
- return appId;
- }
- public void setAppId(String appId) {
- this.appId = appId;
- }
- public String getTimestamp() {
- return timestamp;
- }
- public void setTimestamp(String timestamp) {
- this.timestamp = timestamp;
- }
- public String getNonceStr() {
- return nonceStr;
- }
- public void setNonceStr(String nonceStr) {
- this.nonceStr = nonceStr;
- }
- public String getSignature() {
- return signature;
- }
- public void setSignature(String signature) {
- this.signature = signature;
- }
- }
-
- /**
- * 微信js api 支付参数
- */
- public class JsApiPayConfig{
- private String appId;
- private String timeStamp;
- private String nonceStr;
- private String packageStr;
- private String signType;
- private String paySign;
- private JsApiConfig initConfig;
-
- public String getAppId() {
- return appId;
- }
- public void setAppId(String appId) {
- this.appId = appId;
- }
- public String getTimeStamp() {
- return timeStamp;
- }
- public void setTimeStamp(String timeStamp) {
- this.timeStamp = timeStamp;
- }
- public String getNonceStr() {
- return nonceStr;
- }
- public void setNonceStr(String nonceStr) {
- this.nonceStr = nonceStr;
- }
- public String getPackageStr() {
- return packageStr;
- }
- public void setPackageStr(String packageStr) {
- this.packageStr = packageStr;
- }
- public String getSignType() {
- return signType;
- }
- public void setSignType(String signType) {
- this.signType = signType;
- }
- public String getPaySign() {
- return paySign;
- }
- public void setPaySign(String paySign) {
- this.paySign = paySign;
- }
- public JsApiConfig getInitConfig() {
- return initConfig;
- }
- public void setInitConfig(JsApiConfig initConfig) {
- this.initConfig = initConfig;
- }
- }
- }
|