package ************.pay.util;
import cn.stylefeng.guns.core.util.RedisUtils;
import com.alibaba.fastjson.JSONObject;
import com.github.wxpay.sdk.WXPayUtil;
import com.google.gson.Gson;
import lombok.extern.log4j.Log4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;
/**
* 抽取的微信支付工具
*
* @author gc
*/
@Component
public class wxPayUtil {
private Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 微信appid
*/
private static final String APPID = "wx·····3add6";
/**
* 商户号
*/
private static final String mchId = "150····391";
/**
* 商户API密钥
* todo 重置商户密钥
*/
private static final String paternerKey = "GYDh8······5gvbnkiy9yg6";
/**
* 微信appsecret 用于获取用户的openId
*/
private static final String APPSECRET = "4e66c7······f7314ab8c014d";
/**
* 终端IP spbilCreateIp
*/
private static final String spbilCreateIp = "47.···.···.202";
/**
* 统一回调地址 notifyUrl+"/xdcj"
* <p>
*/
private static final String notifyUrl = "http://····.com";
/***
* get 请求发送
*/
public static String doGet(String urls) throws Exception {
URL url = new URL(urls);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(true);
connection.setDoInput(true);
connection.connect();
//获取返回的字符
InputStream inputStream = connection.getInputStream();
int size = inputStream.available();
byte[] bs = new byte[size];
inputStream.read(bs);
String message = new String(bs, "UTF-8");
return message;
}
/**
* 获取微信 access_token (信息token)
*/
public static String getAccessToken() {
try {
String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
+ APPID + "&secret=" + APPSECRET;
String message = doGet(accessTokenUrl);
//获取access_token
JSONObject jsonObject = JSONObject.parseObject(message);
String accessToken = jsonObject.getString("access_token");
String expires_in = jsonObject.getString("expires_in");
return accessToken;
}catch (Exception e){
e.printStackTrace();
}
return null ;
}
/**
* 获取微信 AuthToken (授权token -用户登录授权 )
*/
public static JSONObject getAuthToken(String code) {
try {
String accessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + APPID + "&secret=" + APPSECRET
+ "&code=" + code + "&grant_type=authorization_code" ;
String message = doGet(accessTokenUrl);
//获取access_token
JSONObject jsonObject = JSONObject.parseObject(message);
System.err.println("获取微信 AuthToken :"+ jsonObject);
return jsonObject;
}catch (Exception e){
e.printStackTrace();
}
return null ;
}
/**
* 获取微信 code
*/
public static void getCode(String userName , HttpServletRequest request ,HttpServletResponse response) throws IOException {
System.err.println("获取微信 code,openId --- 获取到的userName:"+userName);
String redirect_uri= URLEncoder.encode(notifyUrl+"/api/designer/getUserWXCode?userName="+userName, "UTF-8");
System.err.println(redirect_uri);
/**
* 简单获取openid的话参数response_type与scope与state参数固定写死即可
*/
String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+APPID+"&redirect_uri="+redirect_uri+"&response_type=code&scope=snsapi_base&state=123#wechat_redirect" ;
//这里请不要使用get请求单纯的将页面跳转到该url即可
System.err.println(url);
response.sendRedirect(url);
}
/**
* 根据code获取openId
*/
public static String getOpenId(String code) throws Exception {
System.err.println("传过来的code:----"+code);
String accessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+APPID+"&secret="+APPSECRET+"&code="+code+"&grant_type=authorization_code";
String message = doGet(accessTokenUrl);
System.err.println("获取的message:"+message);
//获取openid 返回前端
JSONObject jsonObject = JSONObject.parseObject(message);
System.err.println("获取的jsonObject:"+jsonObject);
String openId = jsonObject.getString("openid");
return openId ;
}
/**
* 查看用户是否关注公众号
*/
public static Boolean isAttentionGZH(String openId) throws Exception {
String accessToken = getAccessToken();
String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="+accessToken+"&openid="+openId+"&lang=zh_CN" ;
String msg = doGet(url);
System.err.println("查看用户是否关注公众号:"+msg);
JSONObject jsonObject = JSONObject.parseObject(msg);
String subscribe = jsonObject.getString("subscribe");
if(null != subscribe && "1".equals(subscribe)){
return true ;
}
return false;
}
/**
* 获取用户信息
*/
public static JSONObject getGZHUserInfo(RedisUtils redisUtils , String openId) throws Exception {
String accessToken = redisUtils.getKey("accessToken");
if (null == accessToken) {
accessToken = wxPayUtil.getAccessToken();
redisUtils.putKey("accessToken", accessToken, true, 7000);
}
String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="+accessToken+"&openid="+openId+"&lang=zh_CN" ;
String msg = doGet(url);
System.err.println("查看用户信息:"+msg);
JSONObject jsonObject = JSONObject.parseObject(msg);
return jsonObject;
}
/**
* 获取用户信息
*/
public static JSONObject getUserInfo( String code ,String openId) throws Exception {
JSONObject jsonObject = wxPayUtil.getAuthToken(code);
String accessToken = jsonObject.get("access_token").toString();
String url = "https://api.weixin.qq.com/sns/userinfo?access_token="+accessToken+"&openid="+openId+"&lang=zh_CN" ;
String msg = doGet(url);
System.err.println("获取用户信息:"+msg);
JSONObject uerInfo = JSONObject.parseObject(msg);
return uerInfo;
}
/**
* 获取用户信息
*/
public static JSONObject getUserInfo( Object accessToken ,Object openId) throws Exception {
String url = "https://api.weixin.qq.com/sns/userinfo?access_token="+accessToken+"&openid="+openId+"&lang=zh_CN" ;
String msg = doGet(url);
System.err.println("获取用户信息:"+msg);
JSONObject uerInfo = JSONObject.parseObject(msg);
return uerInfo;
}
/**
* 微信支付的统一下单工具
*
* @param openId 用户openId
* @param payMoney 支付金额 单位:元
* @param orderNum 订单金额
* @param title 支付标题(或者买的商品名)
* @param wxNotifyUrl (支付回调地址 -- /xxPay )
* @param request
* @param response
* @throws Exception
*/
public void wxPrepay(BigDecimal payMoney, String orderNum, String title, String wxNotifyUrl,
HttpServletRequest request, HttpServletResponse response, String openId,String WXTradeType) throws Exception {
logger.info("-------------------------------调起微信支付--------------------------------------");
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
// 微信小程序ID
packageParams.put("appid", APPID);
// 商户ID
packageParams.put("mch_id", mchId);
// 随机字符串(32位以内) 这里使用时间戳
packageParams.put("nonce_str", WXPayUtil.generateNonceStr());
// 支付主体名称 自定义 商品描述
packageParams.put("body", title);
//编号自定义以时间戳+随机数+商品ID
packageParams.put("out_trade_no", orderNum);
// 价格 自定义
packageParams.put("total_fee", payMoney.multiply(new BigDecimal(100)).intValue());
//终端IP
packageParams.put("spbill_create_ip", spbilCreateIp);
//支付返回地址要外网访问的到, localhost不行,调用下面buy方法。(订单存入数据库)
packageParams.put("notify_url", notifyUrl + wxNotifyUrl);
//微信付款类型 ( 0 - JSAPI 1 - NATIVE)
if( "0".equals(WXTradeType)){
//JSAPI
packageParams.put("trade_type", "JSAPI");
//用户的openid
if(null != openId){
packageParams.put("openid", openId);
}
}else {
//微信扫码支付
packageParams.put("trade_type", "NATIVE");
}
//获取sign ,paternerKey 最后这个是自己在微信商户设置的32位密钥
String sign = PayCommonUtil.createSign("UTF-8", packageParams, paternerKey);
packageParams.put("sign", sign);
logger.error("生成签名是:" + sign);
//转成XML
String requestXML = PayCommonUtil.getRequestXml(packageParams);
logger.info(" ------- 包装的请求参数requestXML:" + "\n" + requestXML);
//得到含有prepay_id的XML
String resXml = HttpUtil.postData("https://api.mch.weixin.qq.com/pay/unifiedorder", requestXML);
logger.info("---得到含有prepay_id的XML:" + "\n" + resXml);
// 得到prepay_id
String prepay_id = "";
String code_url = "" ;
if (resXml.indexOf("SUCCESS") != -1) {
Map<String, String> resXmlMap = WXPayUtil.xmlToMap(resXml);
prepay_id = resXmlMap.get("prepay_id");
code_url = resXmlMap.get("code_url");
logger.info("prepay_id:" + prepay_id);
logger.info("code_url:" + code_url);
}
SortedMap<Object, Object> packageP = new TreeMap<Object, Object>();
//注意!!!这里是appId,上面是appid
packageP.put("appId", APPID);
//时间戳
packageP.put("timeStamp", System.currentTimeMillis());
//随机字符串
packageP.put("nonceStr", WXPayUtil.generateNonceStr());
//必须把package写成 "prepay_id="+prepay_id这种形式
packageP.put("package", "prepay_id=" + prepay_id);
if( "1".equals(WXTradeType)){
packageP.put("codeUrl", code_url);
}
//paySign加密
packageP.put("signType", "MD5");
//得到paySign
String paySign = PayCommonUtil.createSign("UTF-8", packageP, paternerKey);
packageP.put("paySign", paySign);
//将packageP数据返回给小程序
Gson gson = new Gson();
String json = gson.toJson(packageP);
PrintWriter pw = response.getWriter();
pw.write(json);
pw.close();
}
}
//下面这个是controller的回调代码
/**
* 微信支付的回调函数 回调的就是这个方法
* 上面参数 packageParams.put("notify_url", "http://你的IP地址/order/buy.action");
*
* @param request
* @param response
* @throws Exception
*/
@RequestMapping("/wxNotifyUrl")
public void wxToBuy(HttpServletRequest request, HttpServletResponse response) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()));
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
//sb为微信返回的xml
String notityXml = sb.toString();
String resXml = "";
Map map = XMLUtil.doXMLParse(notityXml);
String returnCode = (String) map.get("return_code");
//返回信息
String returnMsg = (String) map.get("return_msg");
// 实际支付订单的金额 单位:分
String payMoney = (String) map.get("total_fee");
// 时间戳
String nonce_str = (String) map.get("nonce_str");
//商户订单号
String orderNum = (String) map.get("out_trade_no");
//查看订单
DesignerRegisterOrder registerOrder = registerOrderService.selectByOrderNum(orderNum);
registerOrder.setPayDate(new Date());
if (returnCode.equals("SUCCESS")) {
//更新业务逻辑
Boolean bool = registerOrderService.updatePaySuccess(orderNum);
if (bool) {
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
} else {
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
}
} else {
Boolean bool = registerOrderService.updatePayLose(orderNum);
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
}
BufferedOutputStream out = new BufferedOutputStream(
response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
}