最近在负责公司的微信扫码支付,网上的扫码支付文章写的一言难尽,所以想自己写一篇心得,帮助需要的人。
开发之前呢,必须要去看看微信的开发api,弄明白了流程剩下的就好办了。废话少说,接下来就来Coding吧
- 第一步是引入依赖:Native支付除了基本的依赖之外还需要的依赖有以下这些
<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.3.3</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.0.3</version>
</dependency>
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.5</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.45</version>
2. 创建WeChatConfig类
/** * 微信支付配置文件 * @author lrh * */ public class WeChatConfig { /** * 微信服务号APPID */ public static String APPID="xxxxxx"; /** * 微信支付的商户号 */ public static String MCHID="xxxxxx"; /** * 微信支付的API密钥 */ public static String APIKEY="xxxxxx"; /** * 微信支付成功之后的回调地址【注意:当前回调地址必须是公网能够访问的地址】 * 这里我是用了natapp来对本地进行穿透,本地调试的时候记得修改 */ public static String WECHAT_NOTIFY_URL_PC="http://68jhuv.natappfree.cc/chevip_bms/app/zcp/wechat_notify_url_pc"; /** * 微信统一下单API地址 */ public static String UFDODER_URL="https://api.mch.weixin.qq.com/pay/unifiedorder"; }
3. 创建微信统一下单api下的其他字段的entity-->
import lombok.Data; /** * 微信支付需要的入参 * * @author lrh */ @Data public class WeChatParams { public String total_fee;//订单金额:以分钱为单位 public String body;//商品名称 public String out_trade_no;//商户订单号 public String attach;//附加参数 }
4. 接下来就是根据微信的api文档,转换成对应的格式来进行HttpClient请求。工具类我放在最后面提供
import java.awt.image.BufferedImage; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import com.chevip.bms.modules.Service.wechat.config.WeChatConfig; import com.chevip.bms.modules.Service.wechat.entity.WeChatDto; import com.chevip.bms.modules.Service.wechat.utils.HttpClientUtil; import com.chevip.bms.modules.Service.wechat.utils.PayForUtil; import com.chevip.bms.modules.Service.wechat.utils.XMLUtil; import com.chevip.framework.utils.PgsApiUtils; import lombok.extern.slf4j.Slf4j; import com.google.zxing.common.BitMatrix; @Slf4j public class WeixinPay { private static final int BLACK = 0xff000000; private static final int WHITE = 0xFFFFFFFF; /** * 获取微信支付的二维码地址 * * @return * @throws Exception * @author lrh */ public static String getCodeUrl(WeChatDto ps) throws Exception { /** * 账号信息 */ String appid = WeChatConfig.APPID;//微信服务号的appid String mch_id = WeChatConfig.MCHID; //微信支付商户号 String key = WeChatConfig.APIKEY; // 微信支付的API密钥 String notify_url = WeChatConfig.WECHAT_NOTIFY_URL_PC;//回调地址【注意,这里必须要使用外网的地址】 String ufdoder_url = WeChatConfig.UFDODER_URL;//微信下单API地址 String trade_type = "NATIVE"; //类型【网页扫码支付】 /** * 时间字符串 */ String currTime = PayForUtil.getCurrTime(); String strTime = currTime.substring(8, currTime.length()); String strRandom = PayForUtil.buildRandom(4) + ""; String nonce_str = strTime + strRandom; /** * 参数封装 */ SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>(); packageParams.put("appid", appid); packageParams.put("mch_id", mch_id); packageParams.put("nonce_str", nonce_str);//随机字符串 packageParams.put("body", ps.getBody());//支付的商品名称 packageParams.put("out_trade_no", ps.getOut_trade_no());//交易订单号->我用的是时间戳 packageParams.put("total_fee", ps.getTotal_fee());//支付金额 packageParams.put("spbill_create_ip", PayForUtil.localIp());//客户端主机 packageParams.put("notify_url", notify_url); packageParams.put("trade_type", trade_type); packageParams.put("attach", ps.getAttach()); String sign = PayForUtil.createSign("UTF-8", packageParams, key); //获取签名 packageParams.put("sign", sign); String requestXML = PayForUtil.getRequestXml(packageParams);//将请求参数转换成String类型 log.info("微信支付请求参数的报文" + requestXML); String resXml = HttpClientUtil.postData(ufdoder_url, requestXML); //解析请求之后的xml参数并且转换成String类型 Map map = XMLUtil.doXMLParse(resXml); log.info("微信支付响应参数的报文" + resXml); String urlCode = (String) map.get("code_url"); return urlCode; } }
上面的代码请求返回的是url_code ,其中需要将字段转换成微信所需要的xml格式。
微信是不支持直接返回二维码图片的 ,所以需要将url_code使用zxing转换为二维码图片
5.工具类提供:
package com.chevip.bms.modules.Service.wechat.utils;
import com.alibaba.fastjson.JSON;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
/**
* @author lrh
*/
public class HttpClientUtil {
public static String postData(String url, String data) {
//创建HttpClient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
//创建response对象
CloseableHttpResponse response = null;
//创建POST请求
HttpPost httpPost = new HttpPost(url);
//将data转换为JSON对象
StringEntity stringEntity = new StringEntity(JSON.toJSONString(data), "UTF-8");
//将JSON对象保存到Entity中
httpPost.setEntity(stringEntity);
//设置请求头
httpPost.setHeader("Content-Type", "application/json;charset=utf-8");
try {
response = httpClient.execute(httpPost);
if (response != null) {
return EntityUtils.toString(response.getEntity());
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (httpClient != null) {
httpClient.close();
}
if (response != null) {
response.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
package com.chevip.bms.modules.Service.wechat.utils;
import com.alibaba.fastjson.JSON;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
/**
* @author lrh
*/
public class HttpClientUtil {
public static String postData(String url, String data) {
//创建HttpClient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
//创建response对象
CloseableHttpResponse response = null;
//创建POST请求
HttpPost httpPost = new HttpPost(url);
//将data转换为JSON对象
StringEntity stringEntity = new StringEntity(JSON.toJSONString(data), "UTF-8");
//将JSON对象保存到Entity中
httpPost.setEntity(stringEntity);
//设置请求头
httpPost.setHeader("Content-Type", "application/json;charset=utf-8");
try {
response = httpClient.execute(httpPost);
if (response != null) {
return EntityUtils.toString(response.getEntity());
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (httpClient != null) {
httpClient.close();
}
if (response != null) {
response.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
package com.chevip.bms.modules.Service.wechat.utils;
import lombok.extern.slf4j.Slf4j;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
/**
* 支付通用公共类
* * @author lrh
*/
@Slf4j
public class PayForUtil {
/**
* 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
* @return boolean
*/
public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {
StringBuffer sb = new StringBuffer();
Set es = packageParams.entrySet();
Iterator it = es.iterator();
while(it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
String k = (String)entry.getKey();
String v = (String)entry.getValue();
if(!"sign".equals(k) && null != v && !"".equals(v)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + API_KEY);
//算出摘要
String mysign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toLowerCase();
String tenpaySign = ((String)packageParams.get("sign")).toLowerCase();
return tenpaySign.equals(mysign);
}
/**
* @author chenp
* @Description:sign签名
* @param characterEncoding
* 编码格式
* @param
*
* @return
*/
public static String createSign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {
StringBuffer sb = new StringBuffer();
Set es = packageParams.entrySet();
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
String v = (String) entry.getValue();
if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + API_KEY);
String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
return sign;
}
/**
* @author chenp
* @Description:将请求参数转换为xml格式的string
* @param parameters
* 请求参数
* @return
*/
public static String getRequestXml(SortedMap<Object, Object> parameters) {
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
Set es = parameters.entrySet();
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
String v = (String) entry.getValue();
if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {
sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
} else {
sb.append("<" + k + ">" + v + "</" + k + ">");
}
}
sb.append("</xml>");
return sb.toString();
}
/**
* 取出一个指定长度大小的随机正整数.
*
* @param length
* int 设定所取出随机数的长度。length小于11
* @return int 返回生成的随机数。
*/
public static int buildRandom(int length) {
int num = 1;
double random = Math.random();
if (random < 0.1) {
random = random + 0.1;
}
for (int i = 0; i < length; i++) {
num = num * 10;
}
return (int) ((random * num));
}
/**
* 获取当前时间 yyyyMMddHHmmss
* @author chenp
* @return String
*/
public static String getCurrTime() {
Date now = new Date();
SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");
String s = outFormat.format(now);
return s;
}
/**
* 获取本机IP地址
* @author chenp
* @return
*/
public static String localIp(){
String ip = null;
Enumeration allNetInterfaces;
try {
allNetInterfaces = NetworkInterface.getNetworkInterfaces();
while (allNetInterfaces.hasMoreElements()) {
NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
List<InterfaceAddress> InterfaceAddress = netInterface.getInterfaceAddresses();
for (InterfaceAddress add : InterfaceAddress) {
InetAddress Ip = add.getAddress();
if (Ip != null && Ip instanceof Inet4Address) {
ip = Ip.getHostAddress();
}
}
}
} catch (SocketException e) {
log.warn("获取本机Ip失败:异常信息:"+e.getMessage());
}
return ip;
}
}
package com.chevip.bms.modules.Service.wechat.utils;
import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.apache.commons.lang.StringUtils;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class QRUtil {
private static final int WIDTH = 222; // 二维码宽
private static final int HEIGHT = 222; // 二维码高
private static final int WORDHEIGHT = 235; // 加文字二维码高
/**
* 生成二维码
*/
public static String QREncode(String content, HttpServletResponse response ,String fee,String sLicense,String typeName ) throws WriterException, IOException {
int width = 200; // 图像宽度
int height = 200; // 图像高度
double money = Double.parseDouble(fee) / 100;
Map<EncodeHintType, Object> hints = new HashMap<>();
//内容编码格式
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
// 指定纠错等级
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
//设置二维码边的空度,非负数
hints.put(EncodeHintType.MARGIN, 1);
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
// MatrixToImageWriter.writeToPath(bitMatrix, format, new File("C:\\pic\\zxing.gif").toPath());// 输出原图片
MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF);
BufferedImage bufferedImage = LogoMatrix(MatrixToImageWriter.toBufferedImage(bitMatrix,matrixToImageConfig), new File("C:\\pic\\icon_weipu.png"));
// BufferedImage bufferedImage = LogoMatrix(toBufferedImage(bitMatrix), new File("D:\\logo.png"));
// ImageIO.write(bufferedImage, "gif", new File("C:\\pic\\"+out_trade_no+".gif"));//输出带logo图片
BufferedImage image = insertWords(bufferedImage, sLicense+typeName+"金额为"+money+"元");
System.out.println("输出成功.");
ImageIO.write(image, "png", response.getOutputStream());
//图片转换为base64格式
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(image, "png", os);
String base64img = safeUrlBase64Encode(os.toByteArray());
// org.apache.commons.codec.binary.Base64.encodeBase64String(os.toByteArray());
// Base64 base64 = new Base64();
// String base64img = new String(base64.encode(bytes));
return base64img;
}
public static String safeUrlBase64Encode(byte[] data){
String encodeBase64 = org.apache.commons.codec.binary.Base64.encodeBase64String(data);
String safeBase64Str = encodeBase64.replace('+', '-');
safeBase64Str = safeBase64Str.replace('/', '_');
// safeBase64Str = safeBase64Str.replaceAll("=", "");
return safeBase64Str;
}
/**
* 识别二维码
*/
public static void QRReader(File file) throws IOException, NotFoundException {
MultiFormatReader formatReader = new MultiFormatReader();
//读取指定的二维码文件
BufferedImage bufferedImage =ImageIO.read(file);
BinaryBitmap binaryBitmap= new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(bufferedImage)));
//定义二维码参数
Map hints= new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
Result result = formatReader.decode(binaryBitmap, hints);
//输出相关的二维码信息
System.out.println("解析结果:"+result.toString());
System.out.println("二维码格式类型:"+result.getBarcodeFormat());
System.out.println("二维码文本内容:"+result.getText());
bufferedImage.flush();
}
/**
* 二维码添加logo
* @param matrixImage 源二维码图片
* @param logoFile logo图片
* @return 返回带有logo的二维码图片
*/
public static BufferedImage LogoMatrix(BufferedImage matrixImage, File logoFile) throws IOException{
/**
* 读取二维码图片,并构建绘图对象
*/
Graphics2D g2 = matrixImage.createGraphics();
int matrixWidth = matrixImage.getWidth();
int matrixHeigh = matrixImage.getHeight();
/**
* 读取Logo图片
*/
BufferedImage logo = ImageIO.read(logoFile);
//开始绘制图片
g2.drawImage(logo,matrixWidth/5*2,matrixHeigh/5*2, matrixWidth/5, matrixHeigh/5, null);//绘制
BasicStroke stroke = new BasicStroke(5,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
g2.setStroke(stroke);// 设置笔画对象
//指定弧度的圆角矩形
RoundRectangle2D.Float round = new RoundRectangle2D.Float(matrixWidth/5*2, matrixHeigh/5*2, matrixWidth/5, matrixHeigh/5,20,20);
g2.setColor(Color.white);
g2.draw(round);// 绘制圆弧矩形
//设置logo 有一道灰色边框
BasicStroke stroke2 = new BasicStroke(1,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
g2.setStroke(stroke2);// 设置笔画对象
RoundRectangle2D.Float round2 = new RoundRectangle2D.Float(matrixWidth/5*2+2, matrixHeigh/5*2+2, matrixWidth/5-4, matrixHeigh/5-4,20,20);
g2.setColor(new Color(128,128,128));
g2.draw(round2);// 绘制圆弧矩形
g2.dispose();
matrixImage.flush() ;
return matrixImage ;
}
/**
* 把带logo的二维码下面加上文字
* @param image
* @param words
* @return
*/
private static BufferedImage insertWords(BufferedImage image,String words){
// 新的图片,把带logo的二维码下面加上文字
if (StringUtils.isNotEmpty(words)) {
//创建一个带透明色的BufferedImage对象
BufferedImage outImage = new BufferedImage(WIDTH, WORDHEIGHT, BufferedImage.TYPE_INT_ARGB);
Graphics2D outg = outImage.createGraphics();
setGraphics2D(outg);
// 画二维码到新的面板
outg.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
// 画文字到新的面板
Color color=new Color(183,183,183);
outg.setColor(color);
// 字体、字型、字号
outg.setFont(new Font("微软雅黑", Font.PLAIN, 14));
//文字长度
int strWidth = outg.getFontMetrics().stringWidth(words);
//总长度减去文字长度的一半 (居中显示)
int wordStartX=(WIDTH - strWidth) / 2;
//height + (outImage.getHeight() - height) / 2 + 12
int wordStartY=HEIGHT+10;
// 画文字
outg.drawString(words, wordStartX, wordStartY);
outg.dispose();
outImage.flush();
return outImage;
}
return null;
}
/**
* 设置 Graphics2D 属性 (抗锯齿)
* @param graphics2D
*/
private static void setGraphics2D(Graphics2D graphics2D){
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics2D.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT);
Stroke s = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER);
graphics2D.setStroke(s);
}
}
package com.chevip.bms.modules.Service.wechat.utils; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; public class XMLUtil { /** * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。 * @param strxml * @return * @throws JDOMException * @throws IOException */ public static Map doXMLParse(String strxml) throws JDOMException, IOException { strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\""); if(null == strxml || "".equals(strxml)) { return null; } Map m = new HashMap(); InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8")); SAXBuilder builder = new SAXBuilder(); Document doc = builder.build(in); Element root = doc.getRootElement(); List list = root.getChildren(); Iterator it = list.iterator(); while(it.hasNext()) { Element e = (Element) it.next(); String k = e.getName(); String v = ""; List children = e.getChildren(); if(children.isEmpty()) { v = e.getTextNormalize(); } else { v = XMLUtil.getChildrenText(children); } m.put(k, v); } //关闭流 in.close(); return m; } /** * 获取子结点的xml * @param children * @return String */ public static String getChildrenText(List children) { StringBuffer sb = new StringBuffer(); if(!children.isEmpty()) { Iterator it = children.iterator(); while(it.hasNext()) { Element e = (Element) it.next(); String name = e.getName(); String value = e.getTextNormalize(); List list = e.getChildren(); sb.append("<" + name + ">"); if(!list.isEmpty()) { sb.append(XMLUtil.getChildrenText(list)); } sb.append(value); sb.append("</" + name + ">"); } } return sb.toString(); } }
6. 最后是回调,微信的回调是直接Post我们的接口,所以必须要公网能访问到的接口。
本地测试的时候可以用内网穿透软件
package com.chevip.bms.modules.Service.wechat.service; import com.chevip.auction_order.service.ServiceOrderService; import com.chevip.bms.modules.Service.wechat.config.WeChatConfig; import com.chevip.bms.modules.Service.wechat.dao.WeChatDao; import com.chevip.bms.modules.Service.wechat.entity.WeChatResultEntity; import com.chevip.bms.modules.Service.wechat.utils.PayForUtil; import com.chevip.bms.modules.Service.wechat.utils.XMLUtil; import lombok.extern.slf4j.Slf4j; import org.jdom.JDOMException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.util.*; /** * 微信回调,通过流进行IO * * @author lrh */ @Slf4j @Service public class NotifyService { @Autowired ServiceOrderService serviceOrderService; @Autowired WeChatDao weChatDao; @Transactional public void wxnotify(HttpServletRequest request, HttpServletResponse response) throws IOException, JDOMException { // InputStream inputStream ; // 获取前端传来的请求参数 // inputStream = request.getInputStream(); BufferedReader in = request.getReader(); // 将字节流转化成字符流 // BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); StringBuffer sb = new StringBuffer(); String s; while ((s = in.readLine()) != null) { sb.append(s); } in.close(); // inputStream.close(); //解析xml成map Map<String, String> m = new HashMap<String, String>(); m = XMLUtil.doXMLParse(sb.toString()); //过滤空 设置 TreeMap SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>(); Iterator<String> it = m.keySet().iterator(); while (it.hasNext()) { String parameter = it.next(); String parameterValue = m.get(parameter); String v = ""; if (null != parameterValue) { v = parameterValue.trim(); } packageParams.put(parameter, v); } // 微信支付的API密钥 String key = WeChatConfig.APIKEY; // key log.info("微信支付返回回来的参数:" + packageParams); //判断签名是否正确 if (PayForUtil.isTenpaySign("UTF-8", packageParams, key)) { String resXml = ""; if ("SUCCESS".equals((String) packageParams.get("result_code"))) { String app_id = (String) packageParams.get("appid"); String mch_id = (String) packageParams.get("mch_id"); String openid = (String) packageParams.get("openid"); String is_subscribe = (String) packageParams.get("is_subscribe");//是否关注公众号 //商户订单号 String out_trade_no = (String) packageParams.get("out_trade_no"); //付款金额【以分为单位】 String total_fee = (String) packageParams.get("total_fee"); //微信生成的交易订单号 String transaction_id = (String) packageParams.get("transaction_id");//微信支付订单号 //支付完成时间 String time_end = (String) packageParams.get("time_end"); String attach = (String) packageParams.get("attach"); String result_code = (String) packageParams.get("result_code"); // 处理自己的回调业务 。。。// 保存微信支付订单 。。。// 微信支付成功后更改支付状态 。。。 log.info("支付成功"); //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了. resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; } else { log.info("支付失败,错误信息:" + packageParams.get("err_code")); 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(); } else { log.info("通知签名验证失败"); } } }
陌上人如玉 公子世无双
浙公网安备 33010602011771号