Java对接微信支付(Native支付。创建订单,查询订单,关闭订单,已测试)

1.pom.xml(引入微信支付sdk)



    com.github.wxpay
    wxpay-sdk
    0.0.3

2.Wxpay-Config.properties

# 微信公众账号或开放平台APP的唯一标识
app_id = 

# 财付通平台的商户账号
partner = 

# 财付通平台的商户密钥
partner_key =  

#下面地址需要公网可以访问
# 微信支付结果通知的回调地址
notify_URL = http://qq1334713380.xicp.net:36576/pay/wxPayController/weChatPayNotify
# 微信退款异步回调
refund_notify_URL= http://qq1334713380.xicp.net:36576/pay/wxPayController/refundResult

3.WxPayConfigImpl.java

   import com.github.wxpay.sdk.WXPayConfig;
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    public class WxPayConfigImpl implements WXPayConfig {
    
        /**
         * 加载证书  这里证书需要到微信商户平台进行下载
         */
        private byte[] certData;
    
        private static WxPayConfigImpl INSTANCE;
    
        /**
         * 配置文件加载
         */
        private static Properties prop;

    /**
     * 配置文件名称
     */
    public static String CONFIG_FILE = "WxPay-Config.properties";

    static {
        initProp();
    }

    /**
     * 私有构造,使其通过公共方法创建对象
     *
     * @throws IOException
     */
    private WxPayConfigImpl() {

        InputStream certStream = WxPayConfigImpl.class.getClassLoader().getResourceAsStream("apiclient_cert.p12");

        try {
            certStream.read(this.certData);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                certStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
    }


    /**
     * 获得WxPayConfigImpl实例
     *
     * @return WxPayConfigImpl实例
     * @throws IOException
     */
    public static WxPayConfigImpl getInstance() {
        if (INSTANCE == null) {
            synchronized (WxPayConfigImpl.class) {
                if (INSTANCE == null) {
                    INSTANCE = new WxPayConfigImpl();
                }
            }
        }
        return INSTANCE;
    }

    /**
     * 初始化配置值
     */
    private static void initProp() {
        prop = new Properties();
        try {
            synchronized (prop) {
                InputStream inputStream = AlipayConfig.class.getClassLoader().getResourceAsStream(CONFIG_FILE);
                prop.load(inputStream);
                inputStream.close();
            }
        } catch (IOException e) {
            log.error("日志 =============》: 配置文件WxPay-Config.properties找不到");
            e.printStackTrace();
        }
    }

    /**
     * 获取配置文件信息
     *
     * @return
     */
    public static Properties getProperties() {
        if (prop == null) {
            initProp();
        }
        return prop;
    }

    @Override
    public String getAppID() {
        return prop.getProperty("app_id");
    }

    @Override
    public String getMchID() {
        return prop.getProperty("partner");
    }

    @Override
    public String getKey() {
        return prop.getProperty("partner_key");
    }

    @Override
    public InputStream getCertStream() {
        ByteArrayInputStream certBis;
        certBis = new ByteArrayInputStream(this.certData);
        return certBis;
    }

    @Override
    public int getHttpConnectTimeoutMs() {
        return 2000;
    }

    @Override
    public int getHttpReadTimeoutMs() {
        return 10000;
    }


    public String getSpbillCreateIp() throws UnknownHostException {
        return InetAddress.getLocalHost().getHostAddress();
    }

4.HttpClient.java

import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLContext;

import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
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;

@SuppressWarnings("all")
public class HttpClient {

    private String url;
    private Map param;
    private int statusCode;
    private String content;
    private String xmlParam;
    private boolean isHttps;
        public boolean isHttps() {
        return isHttps;
    }

    public void setHttps(boolean isHttps) {
        this.isHttps = isHttps;
    }

    public String getXmlParam() {
        return xmlParam;
    }

    public void setXmlParam(String xmlParam) {
        this.xmlParam = xmlParam;
    }

    public HttpClient(String url, Map param) {
        this.url = url;
        this.param = param;
    }

    public HttpClient(String url) {
        this.url = url;
    }

    public void setParameter(Map map) {
        param = map;
    }

    public void addParameter(String key, String value) {
        if (param == null) {
            param = new HashMap();
        }
            param.put(key, value);

    }

    public void post() throws ClientProtocolException, IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException {
        HttpPost http = new HttpPost(url);
        setEntity(http);
        execute(http);
    }

    public void put() throws ClientProtocolException, IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException {
        HttpPut http = new HttpPut(url);
        setEntity(http);
        execute(http);
    }

    public void get() throws ClientProtocolException, IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException {
        if (param != null) {
            StringBuilder url = new StringBuilder(this.url);
            boolean isFirst = true;
            for (String key : param.keySet()) {
                if (isFirst) {
                    url.append("?");
                }else{
                    url.append("&");}
                url.append(key).append("=").append(param.get(key));
            }
            this.url = url.toString();
        }
        HttpGet http = new HttpGet(url);
        execute(http);
    }

    /**
     * set http post,put param
     */
    private void setEntity(HttpEntityEnclosingRequestBase http) {
        if (param != null) {
            List nvps = new LinkedList();
            for (String key : param.keySet()) {
                // 参数
                nvps.add(new BasicNameValuePair(key, param.get(key)));
            }
            http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // 设置参数
        }
        if (xmlParam != null) {
            http.setEntity(new StringEntity(xmlParam, Consts.UTF_8));
        }
    }

    private void execute(HttpUriRequest http) throws ClientProtocolException,
            IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException {
                //退款时需要加载证书文件,详情见微信支付,证书文件使用
        //KeyStore keyStore = KeyStore.getInstance("PKCS12");
        //keyStore.load(HttpClient.class.getClassLoader().getResourceAsStream("apiclient_cert.p12"), WxPayConstant.PARTNER.toCharArray());
        CloseableHttpClient httpClient = null;
        try {
            if (isHttps) {
                SSLContext sslContext = SSLContexts.custom()
                        .loadTrustMaterial(null, new TrustStrategy() {
                            // 信任所有
                            @Override
                            public boolean isTrusted(X509Certificate[] chain,
                                                     String authType)
                                    throws CertificateException {
                                return true;
                            }
                        })
                        //.loadKeyMaterial(keyStore,WxPayConstant.PARTNER.toCharArray())
                        .build();
                SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                        sslContext);
                httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
                        .build();
            } else {
                httpClient = HttpClients.createDefault();
            }
            CloseableHttpResponse response = httpClient.execute(http);
            try {
                if (response != null) {
                    if (response.getStatusLine() != null) {
                        statusCode = response.getStatusLine().getStatusCode();
                    }
                    HttpEntity entity = response.getEntity();
                    // 响应内容
                    content = EntityUtils.toString(entity, Consts.UTF_8);
                }
            } finally {
                response.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            httpClient.close();
        }
    }

    public int getStatusCode() {
        return statusCode;
    }

    public String getContent() throws ParseException, IOException {
        return content;
    }
}

5.WxPayServiceImpl.java

import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

@SuppressWarnings("ALL")
@Service
@Transactional(rollbackFor = Exception.class)
public class WxPayServiceImpl implements IWxPayService {

    private WxPayConfigImpl wxPayConfig;

    private WXPay wxpay;

    private static WxPayServiceImpl INSTANCE;

    @Autowired
    private OrderDao orderDao;

    @Autowired
    private OrderService orderService;

    @Autowired
    private PayOrderFlowDao payOrderFlowDao;

    @Autowired
    private UserDao userDao;

    private Properties prop = WxPayConfigImpl.getProperties();

    public WxPayServiceImpl() {
        wxPayConfig = WxPayConfigImpl.getInstance();
        wxpay = new WXPay(wxPayConfig);
    }

    /**
     * 生成微信支付二维码
     *
     * @param outTradeNo 订单号
     * @return
     */
    @Override
    public Map unifiedOrder(String outTradeNo) {
        //订单号合法性校验
        Order order = PayCommonUtil.checkOutTradeNo(outTradeNo, true);

        String totalMoney = (order.getPrice().multiply(new BigDecimal("100"))) + "";

        //组装请求参数
        Map wxPayRequestMap = this.addWxPayParam(outTradeNo);

        //商品描述
        wxPayRequestMap.put("body", "绿马甲灵活用工平台");
        //标价金额
        wxPayRequestMap.put("total_fee", totalMoney.substring(0, totalMoney.lastIndexOf(".")));
        //终端IP
        try {
            wxPayRequestMap.put("spbill_create_ip", wxPayConfig.getSpbillCreateIp());
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        //支付结果通知的回调地址
        wxPayRequestMap.put("notify_url", prop.getProperty("notify_URL"));
        //交易方式
        wxPayRequestMap.put("trade_type", WxPayConstant.NATIVE);

        //将要发送的参数,转换为xml
        try {
            String xmlParam = WXPayUtil.generateSignedXml(wxPayRequestMap, wxPayConfig.getKey());

            Map resultMap = this.getContent(xmlParam, "https://api.mch.weixin.qq.com/pay/unifiedorder");

            Map responseMap = new HashMap(16);
            responseMap.put("codeUrl", resultMap.get("code_url"));
            responseMap.put("outTradeNo", outTradeNo);
            responseMap.put("totalFee", order.getPrice());
            System.out.println(resultMap);

            return responseMap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 查询支付状态
     *
     * @param outTradeNo 订单号
     * @return
     */
    @Override
    public Result orderQuery(String outTradeNo) {
        //订单号合法性校验
        Order order = PayCommonUtil.checkOutTradeNo(outTradeNo, true);

        //组装请求参数
        Map wxPayRequestMap = this.addWxPayParam(outTradeNo);

        //将要发送的参数,转换为xml

        String xmlParam = null;
        try {
            xmlParam = WXPayUtil.generateSignedXml(wxPayRequestMap, wxPayConfig.getKey());

            int i = 0;
            //轮询
            while (true) {
                //查询支付状态
                Map map = this.getContent(xmlParam, "https://api.mch.weixin.qq.com/pay/orderquery");
                if (map == null) {
                    return ResultUtil.error("支付错误");
                } else if ("FAIL".equals(map.get("trade_state"))) {
                    return ResultUtil.error((String) map.get("return_msg"));
                }
                if ("SUCCESS".equals(map.get("trade_state"))) {

                    return ResultUtil.success("支付成功");
                } else if ("CLOSED".equals(map.get("trade_state"))) {
                    return ResultUtil.error("订单已关闭");
                } else if ("PAYERROR".equals(map.get("trade_state"))) {
             
                    return ResultUtil.error("支付失败");
                }

                //间隔三秒
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                i++;
                //防止无限的轮询下去,增加一个计数器
                if (i >= 20) {
                    return ResultUtil.error("二维码超时");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResultUtil.error("支付错误");
    }

    /**
     * 关闭订单
     *
     * @param outTradeNo 订单号
     * @return
     */
    @Override
    public Result closeOrder(String outTradeNo) {
        //组装请求参数
        Map wxPayRequestMap = this.addWxPayParam(outTradeNo);
        //将要发送的参数,转换为xml
        try {
            String xmlParam = WXPayUtil.generateSignedXml(wxPayRequestMap, wxPayConfig.getKey());
            Map map = this.getContent(xmlParam, "https://api.mch.weixin.qq.com/pay/closeorder");
            if (map == null) {
                return ResultUtil.error("支付关闭错误");
            }
            if (WxPayConstant.SUCCESS.equals(map.get("return_code"))) {
                Result result = this.orderQuery(outTradeNo);
                return result;
            } else {
                if (WxPayConstant.ORDERPAID.equals(map.get("err_code"))) {
                    return ResultUtil.error("订单已支付");
                } else if (WxPayConstant.ORDERCLOSED.equals(map.get("err_code"))) {
                    return ResultUtil.error("订单已关闭");
                } else if (WxPayConstant.SYSTEMERROR.equals(map.get("err_code"))) {
                    return ResultUtil.error("系统错误");
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 退款
     * @param refund 退款实体类
     * @return
     */
    @Override
    public Map refund(OrderRefund refund) {

        String totalMoney = (refund.getPayPrice().multiply(new BigDecimal("100"))) + "";

        String refundMoney = (refund.getRufundPrice().multiply(new BigDecimal("100"))) + "";

        //组装请求参数
        Map wxPayRequestMap = this.addWxPayParam(refund.getOrderId().getOrderUUID());

        //退款订单号
        wxPayRequestMap.put("out_refund_no", refund.getOrderRefundId());
        //订单金额
        wxPayRequestMap.put("total_fee", totalMoney.substring(0, totalMoney.lastIndexOf(".")));
        //退款金额
        wxPayRequestMap.put("refund_fee", refundMoney.substring(0, refundMoney.lastIndexOf(".")));

        //退款结果通知的回调地址
        wxPayRequestMap.put("notify_url", prop.getProperty("refund_notify_URL"));

        //将要发送的参数,转换为xml
        try {
            String xmlParam = WXPayUtil.generateSignedXml(wxPayRequestMap, wxPayConfig.getKey());
            return this.getContent(xmlParam, "https://api.mch.weixin.qq.com/secapi/pay/refund");

        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 查询退款
     *
     * @param outTradeNo 订单号
     * @return
     */
    @Override
    public Map refundQuery(String outTradeNo) {
        //组装请求参数
        Map wxPayRequestMap = this.addWxPayParam(outTradeNo);
        //将要发送的参数,转换为xml
        try {
            String xmlParam = WXPayUtil.generateSignedXml(wxPayRequestMap, wxPayConfig.getKey());
            return this.getContent(xmlParam, "https://api.mch.weixin.qq.com/pay/refundquery");

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 组装调用微信支付接口所需的基本参数
     *
     * @param outTradeNo
     * @return
     */
    private Map addWxPayParam(String outTradeNo) {

        //组装请求参数
        Map wxPayRequestMap = new HashMap(16);
        //公众账号ID
        wxPayRequestMap.put("appid", wxPayConfig.getAppID());
        //商户号
        wxPayRequestMap.put("mch_id", wxPayConfig.getMchID());
        //随机字符串
        wxPayRequestMap.put("nonce_str", WXPayUtil.generateNonceStr());
        //商户订单号
        wxPayRequestMap.put("out_trade_no", outTradeNo);

        return wxPayRequestMap;
    }

    /**
     * 发送支付请求,返回结果
     *
     * @param xmlParam 请求参数
     * @param url      请求url
     * @return
     * @throws Exception
     */
    private Map getContent(String xmlParam, String url) throws Exception {
        //发送请求
        HttpClient httpClient = new HttpClient(url);
        httpClient.setHttps(true);
        httpClient.setXmlParam(xmlParam);
        httpClient.post();

            //获得结果
            String content = httpClient.getContent();
            //使用工具类解析要返回的map
            Map responseMap = WXPayUtil.xmlToMap(content);
            return responseMap;
    
        }
    }

6.WxPayDecodeUtil.java

import cn.exrick.xboot.lvmajia.pay.config.WxPayConfigImpl;
import org.springframework.util.Base64Utils;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class WxPayDecodeUtil {
    private static final String ALGORITHM = "AES";

    private static final String ALGORITHM_MODE_PADDING = "AES/ECB/PKCS7Padding";

    private static SecretKeySpec secretKey = new SecretKeySpec(MD5Util.MD5Encode(WxPayConfigImpl.getInstance().getKey(), "UTF-8").toLowerCase().getBytes(), ALGORITHM);
	  //退款结果解密
    public static String decryptData(String base64Data) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        return new String(cipher.doFinal(Base64Utils.decode(base64Data.getBytes())));
    }

}

7.WxPayNotifyController.java

import cn.hutool.core.util.StrUtil;
import com.github.wxpay.sdk.WXPayUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@RestController
@RequestMapping("/xboot/pay/wxPayController")
@Api(value = "微信支付异步回调接口")
@Slf4j
public class WxPayNotifyController {
    
    @Autowired
    private IWxPayService wxPayService;

    @Autowired
    private IPayOrderFlowService payOrderFlowService;

    @Autowired
    private UserDao userDao;

    @Autowired
    private OrderService orderService;

    @Autowired
    private OrderRefundService orderRefundService;

    @Autowired
    private DictDataDao dictDataDao;

    @Autowired
    private DictDao dictDao;

    /**
     * 微信支付结果通知回调接口
     *
     * @param request
     * @param response
     * @throws IOException
     */
    @RequestMapping("/weChatPayNotify")
    @ApiOperation("微信支付结果通知回调接口")
    public void weChatPayNotify(HttpServletRequest request, HttpServletResponse response) {
        //读取参数
        InputStream inputStream = null;
        BufferedReader in = null;
        BufferedOutputStream out = null;
        StringBuffer sb = new StringBuffer();
        try {
            inputStream = request.getInputStream();

            String s;
            in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
            while ((s = in.readLine()) != null) {
                sb.append(s);
            }


            //解析xml成map
            Map resultMap = new HashMap<>(16);
            resultMap = WXPayUtil.xmlToMap(sb.toString());

            //过滤空 设置 TreeMap
            SortedMap packageParams = new TreeMap<>();
            Set keySet = resultMap.keySet();
            for (String key : keySet) {
                String value = resultMap.get(key);
                String v = "";
                if (StrUtil.isNotBlank(value)) {
                    v = value.trim();
                }
                packageParams.put(key, v);
            }

            //判断签名是否正确
            if (WXPayUtil.isSignatureValid(packageParams, WxPayConfigImpl.getInstance().getKey())) {

                //处理业务开始
                Map requestMap = new HashMap(16);
                if ("SUCCESS".equals((String) packageParams.get("return_code"))) {

                    //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
                    requestMap.put("return_code", "SUCCESS");
                    requestMap.put("return_msg", "OK");
                    System.out.println("通知签名验证成功");
                    /**
                     * 业务处理
                     */
                } else {

                    requestMap.put("return_code", "FAIL");
                    requestMap.put("return_msg", "报文为空");

                }
                String xmlParam = WXPayUtil.mapToXml(requestMap);
                out = new BufferedOutputStream(
                        response.getOutputStream());
                out.write(xmlParam.getBytes());
                out.close();
            } else {
                log.info("通知签名验证失败");
                System.out.println("通知签名验证失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            ExceptionCast.cast(ResultEnum.INVALID_PARAM);
        } finally {
            try {

                in.close();
                inputStream.close();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

  

    /**
     * 微信退款结果通知接口
     *
     * @return
     */
    @RequestMapping("/refundResult")
    @ApiOperation("微信退款结果通知接口")
    public void refundResult(HttpServletRequest request, HttpServletResponse response) {
        //读取参数
        InputStream inputStream = null;
        BufferedReader in = null;
        BufferedOutputStream out = null;
        try {
            StringBuffer sb = new StringBuffer();
            inputStream = request.getInputStream();

            String s;
            in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
            while ((s = in.readLine()) != null) {
                sb.append(s);
            }

            //解析xml成map
            Map resultMap = new HashMap<>(16);
            resultMap = WXPayUtil.xmlToMap(sb.toString());
            //处理业务开始
            Map requestMap = new HashMap(16);
            if (resultMap != null && resultMap.size() > 0) {
                //退款结果解密
                String reqInfo = WxPayDecodeUtil.decryptData(resultMap.get("req_info"));
                //得到退款结果信息
                Map map = WXPayUtil.xmlToMap(reqInfo);
                if ("SUCCESS".equals(map.get("refund_status"))) {
                    /**
                     * 业务处理
                     */
                     //通知微信.异步确认成功
                    requestMap.put("return_code", "SUCCESS");
                    requestMap.put("return_msg", "OK");

                } else{
                    
                }
                
            } else {

               requestMap.put("return_code", "FAIL");
               requestMap.put("return_msg", "报文为空");

            }
            String xmlParam = WXPayUtil.mapToXml(requestMap);
            out = new BufferedOutputStream(
                    response.getOutputStream());
            out.write(xmlParam.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
            ExceptionCast.cast(ResultEnum.INVALID_PARAM);
        } finally {
            try {

                in.close();
                inputStream.close();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

你可能感兴趣的:(java)