Java之微信支付JSAPI

JSAPI支付介绍:

JSAPI支付是用户在微信中打开商户的H5页面,商户在H5页面通过调用微信支付提供的JSAPI接口调起微信支付模块完成支付。
应用场景有:
◆ 用户在微信公众账号内进入商家公众号,打开某个主页面,完成支付。
◆ 用户的好友在朋友圈、聊天窗口等分享商家页面连接,用户点击链接打开商家页面,完成支付。
◆ 将商户页面转换成二维码,用户扫描二维码后在微信浏览器中打开页面后完成支付。

这里使用将商户页面转换成二维码,用户扫描二维码后在微信浏览器中打开页面后完成支付。

一.JSAPI支付前期准备

JSAPI支付需要准备 :公众号和商户号

1.微信支付需要进行申请
Java之微信支付JSAPI
2.公众号平台- 网页授权 和JS授权

网页授权 Java之微信支付JSAPI
JS授权

Java之微信支付JSAPI

3.微信支付商户平台-支付授权目录

**ps:出现添加后页面没有反应。**
 1.添加支付目录后,按流程正确输入操作密码后。界面会跳回来,这个时候发现并没有添加成功。
 2.接下来不要刷新网页,也不要点击别的模块。再添加一次刚才添加的目录。 
 3.这个时候,你会发现不用输入操作密码了,然后,目录也添加成功了

支付授权目录

ps:最好选择为 https//

Java之微信支付JSAPI

二、获取主要参数

   	微信商户:
   	Appid:xxxx;
   	mch_id:xx
   	APi:xxx;
   
  	公众号:
   	Appid: xx 
   	AppSecret:xx
 

1、商户号平台参数

商户号Appid的获取方法:微信支付商户后台(pay.weixin.qq.com) -> 【账户中心】->【账户设置-商户信息】->微信支付商户号。
Java之微信支付JSAPI
微信支付商户号mch_id

Java之微信支付JSAPI

商户密匙API:在微信支付商户平台(pay.weixin.qq.com),进入【账户中心】->【账户设置-API安全】->【设置密钥】,自助设置32位API密钥即可。如下图所示:
Java之微信支付JSAPI

*注意:请事先将需设置的密钥用文档记录,设置成功后不支持查看,只支持修改重设。

2.公众号参数

Appid:xx
AppSecret:xx

ps:注意设置服务器白名单。

Java之微信支付JSAPI

3、配置完API密钥后,请记得在【产品中心 – JSAPI支付】,开通JSAPI支付。

Java之微信支付JSAPI

ed:微信支付开通完成。

三、开始开发

微信支付-》微信支付回调-》验证回调的签名支付信息-》支付成功
微信退款-》微信退款回调-》解密回调信息-》退款成功

1.获取用户的openid

这里使用的是:网页授权获取用户openid
具体而言,网页授权流程分为四步:

  1. 引导用户进入授权页面同意授权,获取code
  2. 通过code换取网页授权access_token(与基础支持中的access_token不同)
  3. 如果需要,开发者可以刷新网页授权access_token,避免过期
  4. 通过网页授权access_token和openid获取用户基本信息(支持UnionID机制)

网站链接转二维码地址:https://cli.im/

//TODO 回调接口
@RequestMapping("/gzh")
public class GzhHtmlController {
	@RequestMapping(value = "/queryFee")
	public ModelAndView queryFee(String code) {
		ModelAndView mv = new ModelAndView();
		String openid=openidUtil.htmlGetOpenid(code);
		mv.addObject("openid",openid);
		mv.setViewName("gzh/index");
		return mv;
	}
}

getOpenid方法:

	/**
	 * 
	 * @param appid 公众号appid
	 * @param appSecret:xx 公众号appsecret
	 * @param code
	 * @return
	 */
public String getOpenid(String appid, String appSecret:xx, String code) {
		try {
			RestTemplate restTemplate = new RestTemplate();

			String url = String.format(
					"https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code",
					appid, appSecret:xx, code);
			String res = restTemplate.getForObject(url, String.class);
			ObjectMapper mapper = new ObjectMapper();
			@SuppressWarnings("rawtypes")
			HashMap m = mapper.readValue(res, HashMap.class);
			String openid = (String) m.get("openid");
			return openid;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

回调地址:https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=redirect_uri&response_type=code&scope=snsapi_base&state=123#wechat_redirect

地址中的参数:
1.appid=公众号的appid
2.redirect_uri= https:域名/项目名/gzh/queryFee 地址需使用urlEncode 对链接进行处理
3.response_type=code&scope=snsapi_base&state=123#wechat_redirect 默认

2.支付代码
https://blog.csdn.net/daotiao0199/article/details/85284038

3.退款
回调解密:

AESUtil.java

package cn.edu.cqu.paymentservice.utils.jmutil;

import cn.edu.cqu.paymentservice.utils.wxpay.WXPayUtil;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Map;

/**
 * @author jing.huang
 * @function
 * @date 2018年1月10日
 * @version
 */
public class AESUtil {
	/**
	 * 密钥算法
	 */
	private static final String ALGORITHM = "AES";
	/**
	 * 加解密算法/工作模式/填充方式
	 */
	private static final String ALGORITHM_MODE_PADDING = "AES/ECB/PKCS5Padding";
	/**
	 * 生成key
	 */
	private static SecretKeySpec key = new SecretKeySpec(
			MD5.MD5Encode("api密匙").toLowerCase().getBytes(), ALGORITHM);

	/**
	 * AES加密
	 *
	 * @param data
	 * @return
	 * @throws Exception
	 */
	public static String encryptData(String data) throws Exception {
		// 创建密码器
		Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING);
		// 初始化
		cipher.init(Cipher.ENCRYPT_MODE, key);
		return Base64Util.encode(cipher.doFinal(data.getBytes()));
	}

	/**
	 * AES解密
	 *
	 * @param base64Data
	 * @return
	 * @throws Exception
	 */
	public static String decryptData(String base64Data) throws Exception {
		Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING);
		cipher.init(Cipher.DECRYPT_MODE, key);
		return new String(cipher.doFinal(Base64Util.decode(base64Data)));
	}

	public static void main(String[] args) throws Exception {

		String A = "<xml><return_code>SUCCESS</return_code><appid><![CDATA[wx6ee8f89d58e108ad]]></appid><mch_id><![CDATA[1389309602]]></mch_id><nonce_str><![CDATA[6c1060a9bce50ae1dbb99185a3addc2a]]></nonce_str><req_info><![CDATA[5HOIoMIqBE6kfuOI96rWcq7egyPUHd0wPscqU2ADA/TKchAZIbUQQbGGPbLvaBq2q3p4oyoowc53seV/I+F977v+IA8C7BAExbftBVIhuKo9C3ii6j8gDmkB3fuc31lLdcQoQqiZWO46voDH+Uc6P4+Q3chOqlZlKITQZ+4YxCe898UBCymgQNEO9LNW3gR6s1cIykfMjgeGjUJ89ugdI3tAIs9nEXvWQmzFSKLurFTn6Juj5B6lf4TwpgKzIZxS6zAM5G3opUU0JeoBwMUyUet49w3yoR+HkvPZr1SWiO5ufXYF41b1IzQh9TBL70byL9/o1s+rxTefOY4JRvbMkN139xoXBe1OWH0cJdux56J1XwV4bdiuk0Eh+FxGtABBzEJxZi5w5nara5VRRka+t+B2MSI0fyOwcYZGJEtMKkQlC1MvST6ht45S/midObIY49uCOuq92VuC/HrdmM88Ge881h4T4ccM4ViLTFW2NrKYxFIDFEp3iwhMWY1FpX7A5pIf1i+FLPUlnp9fvqMurG1gYmc61Etvz6HHlohrS+4uItlCLDkJ/O3ZMHFffmta6J2sxOhMOMq3mkkd8LGYan7InznOWQY/XiAxTO/Txxe3s2RJrbBn+BrmQa3Y2Ps2q5BcxMstH0Ln5rV3qG43cpI2zmVtfL0SFBAKn2IB4AdyaiARp8fwPM+PIt7jd215MDTOw5ac4ZppZ6GoS7jUORIO6DVyBlUwfkkIT8fyDutVtp2NZv4X+9rEpp9nH9hgAUU4OdbFVicv3TgLaNJjzpqIu0114c6mVwVavB6ah37+Qyg2PTvTPcGL3+vqXkfW7jnqc/hRBXAQBITyhAIiZnUV8XsU3pFNvDithFqAOBJiQok0JfdPO8uQSIinxuOyTZsnqBpG/1qSeYrzmQKWJda+TKsoBwlsHG+3oXLITyZ416vQJX6Bvof/5tpofuqekVl6GepRkz6ADkwEet/A7Jsp7+KrQwMyF4cWVra69loNJhpnji4qVTHMbPuyStLfngjzmZdA/aL5qvFYRnAIhOEm9WARwyw9QDY01hdleedm6yghd9FRZam7i9cJIA5q]]></req_info></xml>\n";
		Map<String, String> map = WXPayUtil.xmlToMap(A); //微信sdk工具方法
		String req_info = map.get("req_info");

		// 解密 req_info
		String B = AESUtil.decryptData(req_info);
		System.out.println(B);
		Map<String, String> mapInfo = WXPayUtil.xmlToMap(B);
		System.out.println(mapInfo.get("refund_status"));

		// 加密B
//        System.out.println(encryptData(B));
	}

}

Base64Util.java

package cn.edu.cqu.paymentservice.utils.jmutil;


import java.util.Base64;

/**
 * @author jing.huang
 * @function jdk8支持
 * @date 2018年1月10日
 * @version
 */
public class Base64Util {


    public static byte[] decode(String encodedText){
        final Base64.Decoder decoder = Base64.getDecoder();
        return decoder.decode(encodedText);
    }

    public static String encode(byte[] data){
        final Base64.Encoder encoder = Base64.getEncoder();
        return encoder.encodeToString(data);
    }




}

MD5.java

package cn.edu.cqu.paymentservice.utils.jmutil;

import java.security.MessageDigest;



public class MD5 {
    private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
            "8", "9", "a", "b", "c", "d", "e", "f"};

    /**
     * 转换字节数组为16进制字串
     * @param b 字节数组
     * @return 16进制字串
     */
    public static String byteArrayToHexString(byte[] b) {
        StringBuilder resultSb = new StringBuilder();
        for (byte aB : b) {
            resultSb.append(byteToHexString(aB));
        }
        return resultSb.toString();
    }

    /**
     * 转换byte到16进制
     * @param b 要转换的byte
     * @return 16进制格式
     */
    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n = 256 + n;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    /**
     * MD5编码
     * @param origin 原始字符串
     * @return 经过MD5加密之后的结果
     */
    public static String MD5Encode(String origin) {
        String resultString = null;
        try {
            resultString = origin;
            MessageDigest md = MessageDigest.getInstance("MD5");
            resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultString;
    }



}
上一篇:机器学习Day01


下一篇:sklearn模型使用贝叶斯优化调参