微信公众平台二维码支付
生成的二维码主要是用于PC端H5付款的调用,思路是前端调取获取订单接口,目的是前后端校对价格,代码就不予展示
然后就是根据订单号和价格生成二维码
@ApiOperation(value = "微信生成二维码", httpMethod = "POST", response = ResultJsonBean.class, notes = "")
@RequestMapping(value = "/qrcode", method = {RequestMethod.POST,RequestMethod.GET})
@ResponseBody
@ParentPCUser
public void qrcode(
@ApiParam(value="token")@RequestParam(required = false) String token,
@ApiParam(value="支付金额",required = true)@RequestParam(required = true) Long totalprice,
@ApiParam(value="支付订单号",required = true)@RequestParam(required = true) String orderNo,
HttpServletRequest request,HttpServletResponse response) {
try {
String text = PatriarchWexinPayUtil.weixinPay(orderNo, totalprice*100);
//根据url来生成生成二维码
int width = 300;
int height = 300;
//二维码的图片格式
String format = "gif";
Hashtable hints = new Hashtable();
//内容所使用编码
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
BitMatrix bitMatrix;
try {
bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);
MatrixToImageWriter.writeToStream(bitMatrix, format, response.getOutputStream());
} catch (WriterException e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
然后就是获取code_url工具类
package com.kyd.util.pay;
import com.alibaba.fastjson.JSONArray;
import com.kyd.app_parent.service.vo.WeixinPayVO;
import com.kyd.refund.weixin.util.XmlUtil;
import com.kyd.util.AppException;
import com.kyd.util.Base64Util;
import com.kyd.util.XMLUtil;
import com.swetake.util.Qrcode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.jdom.JDOMException;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.web.client.RestTemplate;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.Security;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;
//import com.swetake.util.Qrcode;
/**
* 验证是否是微信官网的信息(家长端)
* @author litao
*
*/
@Slf4j
@Configuration
public class PatriarchWexinPayUtil implements EnvironmentAware{
public static String AUTH_API = "https://api.weixin.qq.com/sns/oauth2/access_token";
// 构造签名的map
// 构造向微信发送参数的实体类
/*支付宝合作者身份ID*/
private static String MCH_ID;
/*接口名称*/
// private static final String APPID=AppEnv.getInstance().getStringProp("weixin.appid", "wx998423eb9b2d522a");
private static String APPID;//智慧校园的微信appid
/*接口名称*/
private static String QUERY_URL;
private static String PAY_URL;
private static final String KEY="JiaXiaoGongXiangParents0701LoveU";
private static String NOTIFY_URL=null;
private static String appSecret;
@SuppressWarnings("unused")
private static String OPENID;
@SuppressWarnings("unused")
private static String SPBILL_CREATE_IP;
private static Environment env;
/**
* 密钥算法
*/
private static final String ALGORITHM = "AES";
/**
* 加解密算法/工作模式/填充方式
*/
private static final String ALGORITHM_MODE_PADDING = "AES/ECB/PKCS7Padding";
public static String getMchId() {
return MCH_ID;
}
public static String getNotifyPrefix(){
return NOTIFY_URL.substring(0, NOTIFY_URL.lastIndexOf("/"));
}
public static String decodeReqInfo(String req_info) throws Exception {
//1.对加密串A做base64解码,得到加密串B
log.info("~~~~~~~~~~~~~进入decodeReqInfo方法");
byte[] req_bytes = Base64Util.decode(req_info);
log.info("~~~~~~~~~~~~~byte[] req_bytes");
//2.对商户key做md5,得到32位小写key*
SecretKeySpec key = new SecretKeySpec(MD5Util.MD5Encode(KEY, "UTF-8").toLowerCase().getBytes(), ALGORITHM);
log.info("~~~~~~~~~~~~~SecretKeySpec");
//3.用key*对加密串B做AES-256-ECB解密
Security.addProvider(new BouncyCastleProvider());
log.info("~~~~~~~~~~~~~addProvider");
// 创建密码器
Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING,"BC");
log.info("~~~~~~~~~~~~~Cipher");
//使用密钥初始化,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, key);
log.info("~~~~~~~~~~~~~init");
byte[] result = cipher.doFinal(req_bytes);
log.info("~~~~~~~~~~~~~result");
return new String(result, "utf-8");
}
@Override
public void setEnvironment(final Environment environment) {
this.env = environment;
MCH_ID=env.getProperty("weixin.patriarch.mch_id");
APPID=env.getProperty("weixin.patriarch.appid");
QUERY_URL=env.getProperty("weixin.queryurl");
PAY_URL=env.getProperty("weixin.payurl");
OPENID=env.getProperty("weixin.openid");
SPBILL_CREATE_IP=env.getProperty("weixin.spbill_create_ip");
NOTIFY_URL=env.getProperty("weixin.patriarch.notify_url");
appSecret=env.getProperty("weixin.patriarch.appSecret");
}
/**
*@Description: 生成二维码支付
*@parm
*@return
*@Author litao
*@time 2019/10/22 17:14
*@other
*/
public static String weixinPay(String orderno, Long totalprice) throws Exception {
String out_trade_no = orderno; //订单号 (调整为自己的生产逻辑)
String nonceStr=UUID.randomUUID().toString().replace("-", "");
// 回调接口
String trade_type = "NATIVE";
SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();
packageParams.put("appid", APPID);
packageParams.put("mch_id", MCH_ID);
packageParams.put("nonce_str", nonceStr);
packageParams.put("body", "\u4ebf\u8d77\u70b9\u7535\u5b50\u4ea7\u54c1"); //(调整为自己的名称)
packageParams.put("out_trade_no", out_trade_no);
packageParams.put("total_fee", totalprice+""); //价格的单位为分
packageParams.put("spbill_create_ip", SPBILL_CREATE_IP);
packageParams.put("notify_url", NOTIFY_URL);
packageParams.put("trade_type", trade_type);
// String sign = WXSignUtils.createSign("UTF-8", packageParams);
String sign = PayToolUtil.createSign("UTF-8", packageParams,weixinConstant.KEY);
packageParams.put("sign", sign);
String requestXML = PayToolUtil.getRequestXml(packageParams);
System.out.println(requestXML);
String resXml = HttpUtil.postData(PAY_URL, requestXML);
Map map = XMLUtil4jdom.doXMLParse(resXml);
String urlCode = (String) map.get("code_url");
return urlCode;
}
}
PayToolUtil方法
package com.kyd.util.pay;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
public class PayToolUtil {
/**
* 是否签名正确,规则是:按参数名称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();
//System.out.println(tenpaySign + " " + mysign);
return tenpaySign.equals(mysign);
}
/**
* @author
* @date 2016-4-22
* @Description:sign签名
* @param characterEncoding
* 编码格式
* @param parameters
* 请求参数
* @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
* @date 2016-4-22
* @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
*
* @return String
*/
public static String getCurrTime() {
Date now = new Date();
SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");
String s = outFormat.format(now);
return s;
}
}
http工具类,负责发起post请求并获取的返回
package com.kyd.util.pay;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
/**
* http工具类,负责发起post请求并获取的返回
*/
public class HttpUtil {
private final static int CONNECT_TIMEOUT = 5000; // in milliseconds
private final static String DEFAULT_ENCODING = "UTF-8";
public static String postData(String urlStr, String data){
return postData(urlStr, data, null);
}
public static String postData(String urlStr, String data, String contentType){
BufferedReader reader = null;
try {
URL url = new URL(urlStr);
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
conn.setConnectTimeout(CONNECT_TIMEOUT);
conn.setReadTimeout(CONNECT_TIMEOUT);
if(contentType != null)
conn.setRequestProperty("content-type", contentType);
OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), DEFAULT_ENCODING);
if(data == null)
data = "";
writer.write(data);
writer.flush();
writer.close();
reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), DEFAULT_ENCODING));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line);
sb.append("\r\n");
}
return sb.toString();
} catch (IOException e) {
//logger.error("Error connecting to " + urlStr + ": " + e.getMessage());
} finally {
try {
if (reader != null)
reader.close();
} catch (IOException e) {
}
}
return null;
}
}
然后就是生成二维码的工具类
package com.kyd.util.pay;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.ImageIO;
import com.google.zxing.common.BitMatrix;
public class MatrixToImageWriter {
private static final int BLACK = 0xFF000000;
private static final int WHITE = 0xFFFFFFFF;
private MatrixToImageWriter() {
}
public static BufferedImage toBufferedImage(BitMatrix matrix) {
int width = matrix.getWidth();
int height = matrix.getHeight();
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
}
}
return image;
}
public static void writeToFile(BitMatrix matrix, String format, File file)
throws IOException {
BufferedImage image = toBufferedImage(matrix);
if (!ImageIO.write(image, format, file)) {
throw new IOException("Could not write an image of format "
+ format + " to " + file);
}
}
public static void writeToStream(BitMatrix matrix, String format,
OutputStream stream)
throws IOException {
BufferedImage image = toBufferedImage(matrix);
if (!ImageIO.write(image, format, stream)) {
throw new IOException("Could not write an image of format "
+ format);
}
}
}
按照整体流程前端请求就会生成一个直接可以扫描付款的二维码
扫码结果