1.前端传来 code
2.后端通过code 获取微信用户唯一识别id ----> openId
3.根据openId
package com.maege.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.wxpay.sdk.WXPay;
import com.maege.Token.TokenHelper;
import com.maege.Token.TokenModel;
import com.maege.Token.TokenModelStr;
import com.maege.annotation.NoneAuth;
import com.maege.config.AesEncryptUtils;
import com.maege.config.ReturnCommon;
import com.maege.service.OrderService;
import com.maege.service.ProductsService;
import com.maege.wxconfig.HttpClient;
import com.maege.wxconfig.JsonResult;
import com.maege.wxpay_SDK.MyWXConfig;
import com.maege.wxpay_SDK.WXPayConfig;
import com.maege.wxpay_SDK.WXPayConstants;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import com.maege.wxpay_SDK.WXPayUtil;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.URLEncoder;
import java.util.*;
@Controller
@RequestMapping("wx")
public class WXPayController {
private Logger log = LoggerFactory.getLogger(getClass());
@Autowired
ProductsService productsService;
@Autowired
OrderService orderService;
@Resource
private TokenHelper tokenHelper;
/**
* 微信统一下单接口
* id 商品id
* code 前端传来的code 目的为了获取付款用户的唯一openid
* @return
*/
@NoneAuth
@RequestMapping(value = "/prePay", method = RequestMethod.POST)
@ResponseBody
public Map<String,Object> prePay(@RequestBody Map<String,Object> str,HttpServletRequest request){
String id = str.get("id").toString();//商品id
String code = str.get("code").toString();
//id 为下单的id,产品id
//返回参数
Map<String,Object> resMap = new HashMap<>();
//获取请求ip地址
String ip= request.getHeader("x-forwarded-for");
if(ip == null || ip.length() == 0 || "unknow".equalsIgnoreCase(ip)){
ip = request.getHeader("Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknow".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();
}
try {
log.info("id = "+id);
Map<String,String> paraMap = new HashMap<>();
//根据id获取此商品的详细信息
Map<String,Object> map = productsService.profindbyid(id);
String body = (String) map.get("name");//商品名称,数据库查出来的
String out_trade_no = System.currentTimeMillis()+"";//订单号,时间戳生成
String openid = null;
try {//获取openid
openid = getUserInfo(code);
}catch (Exception e){
log.info("openid获取异常={}"+e);
return new HashMap<>();
}
if(openid == null || openid.length()<=0){
log.info("openid ="+openid);
return new HashMap<>();
}
String money = (String) map.get("price");//金额,数据库查出来的
Integer price = Integer.valueOf(money);
log.info("body = "+body);
String nostr = WXPayUtil.generateNonceStr().toUpperCase();//微信随机字符串
paraMap.put("appid", WXPayConstants.APP_ID);
paraMap.put("body", body);//商品名称
paraMap.put("mch_id", WXPayConstants.MCH_ID);//商家id
paraMap.put("nonce_str", nostr);//微信随机字符串
paraMap.put("notify_url", WXPayConstants.CALLBACK_URL);//异步通知地址
paraMap.put("openid", openid);//用户标识,对应下单的用户
paraMap.put("out_trade_no", out_trade_no);//商户订单号
paraMap.put("spbill_create_ip", ip);//ip
paraMap.put("total_fee", price.toString());//标价金额 ,单位分
paraMap.put("trade_type", "JSAPI");//交易类型
String sign = WXPayUtil.generateSignature(paraMap,WXPayConstants.PATERNER_KEY);//第一次签名
paraMap.put("sign",sign);
String xml1 = "<xml>" +
"<appid>"+ WXPayConstants.APP_ID +"</appid>"+
"<body>"+ body +"</body>"+
"<mch_id>"+ WXPayConstants.MCH_ID +"</mch_id>"+
"<nonce_str>"+ nostr +"</nonce_str>"+
"<notify_url>"+ WXPayConstants.CALLBACK_URL +"</notify_url>"+
"<openid>"+ openid +"</openid>"+
"<out_trade_no>"+ out_trade_no +"</out_trade_no>"+
"<spbill_create_ip>"+ ip +"</spbill_create_ip>"+
"<total_fee>"+ price.toString()+"</total_fee>"+
"<trade_type>JSAPI</trade_type>"+
"<sign>"+ sign +"</sign>"+
"</xml>";
String xmlStr = HttpClient.doPostXml(WXPayConstants.UNIFIEDORDER_URL,xml1);
log.info("xmlStr="+xmlStr);
//处理下单业务,将订单存到数据库 ----------- start_1
Map<String,Object> order_map = new HashMap<>();
order_map.put("out_trade_no",out_trade_no);//商户订单号
order_map.put("order_amount",price.toString());//订单金额
order_map.put("paid_amount",price.toString());//实际支付金额
order_map.put("product_id",id);//产品id
order_map.put("buy_counts","1");//购买数量 默认 1
order_map.put("open_id",openid);//用户openid 唯一识别
int flag = orderService.add_order(order_map);
if(flag <= 0){
log.error("创建订单失败");
return ReturnCommon.error("创建订单失败","","500");
}
//----------- end_1
//预支付id: prepay_id
String prepay_id ="";
if(xmlStr.indexOf("SUCCESS") != -1){
//xml 转 map
Map<String,String> mapxml = WXPayUtil.xmlToMap(xmlStr);
prepay_id = mapxml.get("prepay_id").toString();
log.info("prepay_id1="+prepay_id);
}else{
//下单失败删除数据库里的此条订单信息,此处对应上面的下单存数据库但是调用下单信息失败,所以要删除这条信息
int del_flag = orderService.del_order(out_trade_no);
if(del_flag>0){
log.info("订单异常,数据库订单信息已删除");
}
}
log.info("prepay_id2="+prepay_id);
//此处用 appId,timeStamp,nonceStr,package,signType 生成 第二次签名
HashMap<String, String> back = new HashMap<String, String>();
String time = Long.toString(System.currentTimeMillis());
back.put("appId", WXPayConstants.APP_ID);
back.put("timeStamp", time);
back.put("nonceStr", nostr);
back.put("package", "prepay_id=" + prepay_id);
back.put("signType", "MD5");
String sign2 = WXPayUtil.generateSignature(back, WXPayConstants.PATERNER_KEY);
log.info("二次签名后返回给前端的签名证书字符串是:" + sign2);
//返给前端的数据
Map<String,String> fresh = new HashMap<>();
fresh.put("appId", WXPayConstants.APP_ID);
fresh.put("timeStamp", time);
fresh.put("nonceStr", nostr);
fresh.put("package", "prepay_id=" + prepay_id);
fresh.put("signType", "MD5");
fresh.put("paySign", sign2);
fresh.put("out_trade_no",out_trade_no);//商户订单号
log.info("返给前端的数据={}",fresh);
System.out.println("返给前端的数据={}"+fresh);
//封装正常情况下返回数据
resMap.put("success",true);
resMap.put("payMap",fresh);
return ReturnCommon.success("success",resMap,"200");
}catch (Exception e){
resMap.put("error",false);
resMap.put("message","调用同一订单接口错误");
e.printStackTrace();
return ReturnCommon.success("error","调用同一订单接口错误","500");
}
}
/**
* 此订单是否被支付
* 此处用来修改定单状态,
* 支付成功修改定但状态为 1,失败修改为 0
* id: 订单id
* @param request
* @param response
* @return
*/
@RequestMapping("/callBack")
@NoneAuth
public JsonResult callBack(HttpServletRequest request, HttpServletResponse response) {
JsonResult result = new JsonResult();
log.info("微信支付成功,微信发送的callback信息,请注意修改订单信息");
System.out.println("微信支付成功,微信发送的callback信息,请注意修改订单信息");
InputStream is = null;
String resXml = "";
try {
is = request.getInputStream();//获取请求的流信息(这里是微信发的xml格式所有只能使用流来读)
String xml = WXPayUtil.inputStream2String(is);
Map<String, String> notifyMap = WXPayUtil.xmlToMap(xml);//将微信发的xml转map
log.info("接受到微信的订单异步通知="+notifyMap);
System.out.println("接受到微信的订单异步通知="+notifyMap);
if(notifyMap.get("return_code").equals("SUCCESS")){
String ordersNum = notifyMap.get("out_trade_no").toString();//商户订单号
//处理订单状态
String openid = notifyMap.get("openid");
Date zhifutime = new Date();
Integer ordertype = 1;//1支付完成
try {
log.info("商户订单号:"+ordersNum+"--支付状态:"+ordertype+"--支付时间:"+zhifutime+"---complete");
//修改订单状态
int flag = orderService.updatOrder(ordersNum);
if(flag>0){
log.info("定单回调状态修改成功");
//生成流水*************************************
int order = orderService.addflow(notifyMap);
//付款成功 redis中存入登录信息
TokenModelStr model = tokenHelper.create(openid);
String vcode = AesEncryptUtils.encrypt(model.toString2());//Aes 加密token
}
result.setData("SUCCESS");
result.setData("支付回调成功,修改订单状态为支付成功");
//告诉微信服务器收到信息了,不要在调用回调action了========这里很重要回复微信服务器信息用流发送一个xml即可
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
BufferedOutputStream out = new BufferedOutputStream(
response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
System.err.println("返回给微信的值:"+resXml.getBytes());
is.close();
}catch (Exception e){
result.setErrmsg("订单状态修改失败");
}
}
} catch (Exception e) {
log.info("订单回调失败,原因="+e);
e.printStackTrace();
}
return result;
}
/***
* 查询订单状态接口,
* @return
* @throws Exception
*/
@RequestMapping("/findorder")
@ResponseBody
@NoneAuth
public Map<String,Object> findorder( @RequestBody Map<String,Object> str ){
String ordersNum = str.get("out_trade_no").toString();
//根据商户订单号查询该条已支付订单
Map<String,Object> map = orderService.findByid(ordersNum);
Map<String,Object> maptoken = new HashMap<>();
if(!map.isEmpty()){
try {
//获取redis中的token
TokenModelStr model = tokenHelper.getkv(map.get("open_id").toString());
String vcode = AesEncryptUtils.encrypt(model.toString2());//Aes 加密token
maptoken.put("token",vcode);
maptoken.put("username","游客");
}catch (Exception e){
log.info("查询订单出错,"+e);
}
}
return ReturnCommon.success("订单查询成功",maptoken,"200");
}
//获取openid
public String getUserInfo(String code) throws Exception {
System.out.println("code=" + code);
String url = "https://api.weixin.qq.com/sns/jscode2session";
url += "?appid="+WXPayConstants.APP_ID;//自己的appid
url += "&secret="+WXPayConstants.APP_SECRET;//自己的appSecret
url += "&js_code=" + code;
url += "&grant_type=authorization_code";
// url += "&connect_redirect=1";
String res = null;
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
// DefaultHttpClient();
HttpGet httpget = new HttpGet(url); //GET方式
CloseableHttpResponse response = null;
// 配置信息
RequestConfig requestConfig = RequestConfig.custom() // 设置连接超时时间(单位毫秒)
.setConnectTimeout(5000) // 设置请求超时时间(单位毫秒)
.setConnectionRequestTimeout(5000) // socket读写超时时间(单位毫秒)
.setSocketTimeout(5000) // 设置是否允许重定向(默认为true)
.setRedirectsEnabled(false).build(); // 将上面的配置信息 运用到这个Get请求里
httpget.setConfig(requestConfig); // 由客户端执行(发送)Get请求
response = httpClient.execute(httpget); // 从响应模型中获取响应实体
HttpEntity responseEntity = response.getEntity();
System.out.println("响应状态为:" + response.getStatusLine());
if (responseEntity != null) {
res = EntityUtils.toString(responseEntity);
System.out.println("响应内容长度为:" + responseEntity.getContentLength());
System.out.println("响应内容为:" + res);
}
// 释放资源
if (httpClient != null) {
httpClient.close();
}
if (response != null) {
response.close();
}
JSONObject jo = JSON.parseObject(res);
String openid = jo.getString("openid");
System.out.println("openid" + openid);
return openid;
}
}