相信 百度上有好多 写这种支付的 一大堆 有的可能 并不是那么容易懂 。我也是 在自己摸索并结合网上教程 获得一些经验 ,趁着记忆犹新把它写出来 也方便 大家 或者 以后我自己会用到
我简单的 把 一大堆东西简化了 把他们整合写在了一个类里面。下面开始:
(微信 配置的那些东西 相信大家都知道 ,在这里就不多说了 忽略配置)
第一: 了解支付的接口链接和参数信息
官方文档 : https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
接口链接 URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder
官方文档有好多参数 我们只需要其中有用到的就好
需要的参数 :
appid--------------------微信支付分配的公众账号ID(企业号corpid即为此appId)
mch_id------------------微信支付分配的商户号
openid-------------------此参数为微信用户在商户对应appid下的唯一标识
body----------------------商品简单描述
nonce_str---------------随机字符串,长度要求在32位以内。
out_trade_no----------商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|* 且在同一个商户号下唯一
spbill_create_ip-------APP和网页支付提交用户端ip
total_fee----------------订单总金额,单位为分
trade_type-------------JSAPI -JSAPI支付
notify_url---------------异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。
sign----------------------通过签名算法计算得出的签名值
上面就是我们需要的参数
第二、获取openid
获取openid 要先让用户授权得到code再用code去换取
获取code的接口链接:https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=redirectUri&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"
注意: redirect_uri参数:授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理。
处理方法 :java.net.URLEncoder.encode(url, “UTF-8”);
用code换取openid
接口链接:https://api.weixin.qq.com/sns/oauth2/access_token?appid=appid&secret=appsecret&code=code&grant_type=authorization_code
这里我用了一个OpenIdUtil类方便以后直接调用
public class OpenIdUtil
{
/**
* 获取微信用户信息
* @param code 微信端的CODE
* @param classify 用户标示
* @return
*/
public static String oauth2GetOpenid(String code) {
String appid = "替换自己的";
String appsecret = "替换自己的";
//授权(必填)
String grant_type = "authorization_code";
//URL
String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token";
//请求参数
String params = "appid=" + appid + "&secret=" + appsecret + "&code=" + code + "&grant_type=" + grant_type;
//发送请求
String data = HttpSendUtil.sendGet(requestUrl, params);
//解析相应内容(转换成json对象)
JSONObject json = JSONObject.fromObject(data);
//用户的唯一标识(openid)
String openId = String.valueOf(json.get("openid"));
return openId;
}
}
我在这里吧http请求工具类 也贴出来 这样 大家就不用再去到处找了
HttpSendUtil类
public class HttpSendUtil
{
/**
* 向指定URL发送GET方法的请求
*
* @param url
* 发送请求的URL
* @param param
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return URL 所代表远程资源的响应结果
*/
public static String sendGet(String url, String param) {
String result = "";
BufferedReader in = null;
try {
String urlNameString = url + "?" + param;
URL realUrl = new URL(urlNameString);
// 打开和URL之间的连接
URLConnection connection = realUrl.openConnection();
// 设置通用的请求属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
connection.setRequestProperty("Content-Type", "text/xml");
// 建立实际的连接
connection.connect();
// 定义 BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(
connection.getInputStream() ));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
/**
* 向指定 URL 发送POST方法的请求
*
* @param url
* 发送请求的 URL
* @param param
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Content-Type", "text/xml");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(
new InputStreamReader(conn.getInputStream() ));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!"+e);
e.printStackTrace();
}
//使用finally块来关闭输出流、输入流
finally{
try{
if(out!=null){
out.close();
}
if(in!=null){
in.close();
}
}
catch(IOException ex){
ex.printStackTrace();
}
}
return result;
}
}
好了 据需回到 上面 openid获取到了 那我们就开始发送数据了
统一下单 的 接口链接 : https://api.mch.weixin.qq.com/pay/unifiedorder
@RestController
@RequestMapping("/weChatPayController")
@SuppressWarnings({"rawtypes","unchecked"})
public class WeChatPayController {
/**
* 支付
* @author LSJ
* @return
*/
@RequestMapping( value = "orderPay" , method = RequestMethod.GET )
public Map orderPay( HttpServletRequest request, HttpServletResponse response )
{
String out_trade_no = "";//随机生成32个字符内 (唯一)
try {
//拼接统一下单地址参数
Map<String, String> paraMap = new HashMap<String, String>();
//获取请求ip地址
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.getRemoteAddr();
}
if(ip.indexOf(",")!=-1){
String[] ips = ip.split(",");
ip = ips[0].trim();
}
paraMap.put("appid", "自己的APPID");
paraMap.put("body", "描述");
paraMap.put("mch_id", "自己的商户ID");
paraMap.put("nonce_str", WXPayUtil.generateNonceStr());//随机字符串
paraMap.put("openid", openId);
paraMap.put("out_trade_no",out_trade_no );//订单号
paraMap.put("spbill_create_ip", ip); //用户IP 上面已获取
paraMap.put("total_fee", "1");//支付金额 (单位分)
paraMap.put("trade_type", "JSAPI"); //支付类型
paraMap.put("notify_url", "自己的回调地址");// 此路径是微信服务器调用支付结果通知路径
//利用WXPayUtil工具类生成签名
String sign = WXPayUtil.generateSignature(paraMap, "商户密匙");
paraMap.put("sign", sign);
String xml = WXPayUtil.mapToXml(paraMap);//利用WXPayUtil工具类将所有参数(map)转xml格式
String xmlStr = HttpSendUtil.sendPost( WeChatConstant.WX_UNIFIED_ORDER_URL , xml);//发送post请求"统一下单接口"返回预支付id:prepay_id
//以下内容是返回前端页面的json数据
String prepay_id = "";//预支付id
if (xmlStr.indexOf("SUCCESS") != -1) {
Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);
prepay_id = (String) map.get("prepay_id");
//package会用到prepay_id 值的格式例如:”prepay_id= wx2018…250…9981…666”
}
Map<String, String> payMap = new HashMap<String, String>();
payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp()+""); //时间戳
payMap.put("nonceStr", WXPayUtil.generateNonceStr()); //随机字符串
payMap.put("signType", "MD5"); //签名类型
payMap.put("package", "prepay_id=" + prepay_id);
String paySign = WXPayUtil.generateSignature(payMap, "商户密匙");
payMap.put("paySign", paySign);
return payMap;
} catch (Exception e)
{
System.err.println(e);
}
}
}
前端 部分 我就不写出来
以下是我支付成功的回调地址
/**
* 支付成功后的回调
* @author LSJ
* @param request
* @param response
* @throws IOException
*/
@RequestMapping( value = "payCallBack" )
public void payCallBack( HttpServletRequest request,HttpServletResponse response ) throws IOException
{
Map<String,Object> resultMap = null;
try {
System.err.println("支付结果回调...");
//利用WXPayUtil工具类里的方法将XML读取出来
String xmlStr = CommonUtil.parseInputStream(request.getInputStream());
//并转换成MAP 这样就可以拿到xml里想要的数据了
resultMap = CommonUtil.parseXML(xmlStr);
} catch (KeyManagementException | NoSuchAlgorithmException | NoSuchProviderException | IOException e) {
resultMap = Maps.newHashMap();
resultMap.put("return_code", "FAIL");
resultMap.put("return_msg","服务器报错");
}
response.getWriter().write(CommonUtil.getXmlWithMap(resultMap));
response.getWriter().flush();
}
===========上面就是 Java 微信公众号的支付方法 , 写的 不好 大神勿喷
对了 WXPayUtil 工具类 是jar包 是可以用maven仓库获取的
如果有什么不对的地方 或不懂得地方 请大家提出来
我的微信AiMyHear