微信支付-公衆號支付(JAVA)

在這裏插入圖片描述

已上傳至github庫 https://github.com/gaoruiqiang2017/weixinpay.git

開發公衆號支付時,在統一下單接口中要求必傳用戶openid,而獲取openid則需要在公衆平臺設置獲取openid的域名,只有被設置過的域名纔是一個有效的獲取openid的域名,否則將獲取失敗,這也是不好測試的原因

後臺接口

@RestController
@RequestMapping("/weixinGZHpay")
public class WeixinGZHpay {


    @Value("${appid}")
    private String appid;  //公衆賬號id

    @Value("${mchid}")
    private String mchId;  //商戶號

    @Value("${weixinKey}")
    private String weixinKey;  //密匙

    @Value("${weixinAppSecret}")
    private String weixinAppSecret; //	公衆號的appsecret

    @Value("https://api.mch.weixin.qq.com/pay/unifiedorder")
    private String unifiedorderUrl; //統一下單接口

    @Value("weixin.oauth2.url=https://open.weixin.qq.com/connect/oauth2/authorize")
    private String weixinOauth2Url;  //網頁授權獲取code

    @Value("weixin.oauth2.access_token_url=https://api.weixin.qq.com/sns/oauth2/access_token")
    private String accessTokenUrl;   //通過code獲取access_token_url和openid

    @Value("https://127.0.0.1:8080/weixinGZHpay/gzhPay")
    private String redirectUrl;  //授權後重定向的回調鏈接地址, 請使用 urlEncode 對鏈接進行處理


    /**
     * //第一步:用戶同意授權,獲取code
     * 參考:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
     * 如果用戶同意授權,頁面將跳轉至 redirect_uri/?code=CODE&state=STATE。
     *
     * @param httpServletRequest
     * @param httpServletResponse
     * @param orderId             訂單id,先生成自己業務的訂單
     */
    public void getCode(HttpServletRequest httpServletRequest, HttpServletResponse
            httpServletResponse, String orderId) {
        try {
            StringBuffer sb = new StringBuffer();
            sb.append(weixinOauth2Url).append("?").append
                    ("appid=").append(appid).append("&redirect_uri=").append
                    (URLEncoder.encode(redirectUrl, "UTF-8"));
            sb.append("&response_type=code&scope=snsapi_base&state=").append(orderId).append
                    ("#wechat_redirect");        //我使用靜默授權
            StringBuilder sbHtml = new StringBuilder();
            sbHtml.append("<form id=\"weixinggongzhonghao\" name=\"weixinggongzhonghao\" " +
                    "action=\"" + sb.toString()
                    + "\" method=\"" + "post" + "\">");
            sbHtml.append("<input type=\"submit\" value=\"" + "payButton" + "\" " +
                    "style=\"display:none;\"></form>");
            sbHtml.append("<script>document.forms['weixinggongzhonghao'].submit();</script>");
            // 直接將完整的表單html輸出到頁面
            httpServletResponse.setContentType("text/html;charset=utf-8");
            httpServletResponse.getWriter().write(sbHtml.toString());
            httpServletResponse.getWriter().flush();
        } catch (Exception e) {

        }
    }

    /**
     * 第二步:通過code換取網頁授權access_token和用戶openid,並下單獲取調起支付的參數,進入下單頁調起微信支付
     *
     * @param httpServletRequest
     * @param httpServletResponse
     * @param state               從第一步獲取,實際爲訂單id,通過訂單id獲取商品信息
     */
    @RequestMapping("/gzhPay")
    public String gzhPay(HttpServletRequest httpServletRequest, HttpServletResponse
            httpServletResponse, String code, String state, Writer writer, Model model)
            throws Exception {
        String mapStr = "";
        try {
            // // 換區微信access_token和用戶openid
            StringBuffer sb = new StringBuffer();
            sb.append(accessTokenUrl).append("?appid=").append(appid);
            sb.append("&secret=").append(weixinAppSecret);
            sb.append("&code=").append(code);
            sb.append("&grant_type=authorization_code");
            String result = HttpUtil.doPost(accessTokenUrl, sb.toString());
            JSONObject json = JSONObject.parseObject(result);
            String openid = json.getString("openid");
            //獲得openid調用微信統一下單接口
            HashMap<String, String> dataMap = new HashMap<>();
            dataMap.put("appid", appid); //公衆賬號ID
            dataMap.put("mch_id", mchId); //商戶號
            dataMap.put("nonce_str", WXPayUtil.generateNonceStr()); //隨機字符串,長度要求在32位以內。
            dataMap.put("body", "手機"); //商品描述,通過訂單id獲得
            dataMap.put("out_trade_no", state); //商品訂單號
            dataMap.put("total_fee", "1"); //商品金,通過訂單id獲得
            dataMap.put("spbill_create_ip", HttpUtil.getIpAddress(httpServletRequest)); //客戶端ip
            dataMap.put("notify_url", "https://127.0.0.1:8080/weixinGZHpay/notifyUrl"); //通知地址
            // (需要是外網可以訪問的)
            dataMap.put("trade_type", "JSAPI"); //交易類型
            dataMap.put("openid", openid); //商戶號
            //生成簽名
            String signature = WXPayUtil.generateSignature(dataMap, weixinKey);
            dataMap.put("sign", signature);//簽名
            //將類型爲map的參數轉換爲xml
            String requestXml = WXPayUtil.mapToXml(dataMap);
            //發送參數,調用微信統一下單接口,返回xml
            String responseXml = HttpUtil.doPost(unifiedorderUrl, requestXml);
            System.out.print(responseXml);
            Map<String, String> map = WXPayUtil.xmlToMap(responseXml);
            if ("FAIL".equals(map.get("return_code"))) {
                mapStr = map.get("return_msg");
                writer.write(mapStr);
                return "";
            }
            if ("FAIL".equals(map.get("result_code"))) {
                mapStr = map.get("err_code_des");
                writer.write(mapStr);
                return "";
            }
            if ("".equals(map.get("prepay_id")) || map.get("prepay_id") == null) {
                writer.write("prepay_id 爲空");
                return "";
            }
            //成功之後,提取prepay_id,重點就是這個
            HashMap<String, String> params = new HashMap<>();
            params.put("appId", appid);
            params.put("nonceStr", WXPayUtil.generateNonceStr());
            params.put("package", map.get("prepay_id"));
            params.put("signType", "MD5");
            params.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
            //重新簽名
            String paySign = WXPayUtil.generateSignature(params, weixinKey);
            params.put("paySign", paySign);
            //傳給前端頁面
            //在微信瀏覽器裏面打開H5網頁中執行JS調起支付。接口輸入輸出數據格式爲JSON。
            model.addAttribute("param", JSON.toJSON(params));
            return "weixinpay/weixinGZHpay";
            //JS API的返回結果get_brand_wcpay_request爲ok及表示用戶成功完成支付,展示支付成功頁
            // 下一步就是在後臺回調接口處理訂單狀態
        } catch (Exception e) {
            return "異常";
        }
    }

    /**
     * 異步回調(必須有,得發佈到外網)
     *
     * @param unifiedorderUrl
     * @param requestXml
     * @return
     */
    @RequestMapping("/notifyUrl")
    public String notifyUrl(String unifiedorderUrl, String requestXml) {
        System.out.print("進入支付h5回調=====================");
        //如果沒有加redirectUrl,就這這個接口處理訂單信息
        //判斷接受到的result_code是不是SUCCESS,如果是,則返回成功,具體業務具體分析
        // 通知微信.異步確認成功.必寫.不然會一直通知後臺.八次之後就認爲交易失敗了
        String resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" +
                "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
        return resXml; //或者 return "success";
    }
}

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.weixinpay</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--微信支付SDK-->
        <dependency>
            <groupId>com.github.wxpay</groupId>
            <artifactId>wxpay-sdk</artifactId>
            <version>0.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.5</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>javase</artifactId>
            <version>3.0.0</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>

        <finalName>demo</finalName>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <includes>
                    <include>**/*.properties</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>false</filtering>
                <includes>
                    <include>**</include>
                </includes>
            </resource>
        </resources>
    </build>

</project>

util

/**
 * @Description
 * @Date:03
 */
public class HttpUtil {

    public static String doPost(String url, String requestXml) {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse httpResponse = null;
        //創建httpClient連接對象
        httpClient = HttpClients.createDefault();
        //創建post請求連接對象
        HttpPost httpPost = new HttpPost(url);
        //創建連接請求對象,並設置連接參數
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(15000)   //連接服務區主機超時時間
                .setConnectionRequestTimeout(60000) //連接請求超時時間
                .setSocketTimeout(60000).build(); //設置讀取響應數據超時時間
        //爲httppost請求設置參數
        httpPost.setConfig(requestConfig);
        //將上傳參數放到entity屬性中
        httpPost.setEntity(new StringEntity(requestXml, "UTF-8"));
        //添加頭信息
        httpPost.addHeader("Content-type", "text/xml");
        String result = "";
        try {
            //發送請求
            httpResponse = httpClient.execute(httpPost);
            //從相應對象中獲取返回內容
            HttpEntity entity = httpResponse.getEntity();
            result = EntityUtils.toString(entity, "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;

    }

    /**
     * 獲取IP地址
     *
     * @param request
     * @return
     */
    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}

properties

appid=wx12822223?22sss
mchId=149232323312333sss
weixinKey=34234234er2werwerwer
unifiedorderUrl=https://api.mch.weixin.qq.com/pay/unifiedorder
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章