700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > JAVA生成二维码扫码进入h5微信支付宝支付

JAVA生成二维码扫码进入h5微信支付宝支付

时间:2023-06-03 22:50:02

相关推荐

JAVA生成二维码扫码进入h5微信支付宝支付

第一步准备

(1)微信需要的公众服务号和商户号;沙箱有很多问题,所以本人以正式的配置实现,其中公众号需要配置授权路径

其中公众号需配置

商户号需到产品中心 -> 开发配置 -> 支付配置 ->添加JSAPI支付

(2)支付宝需要的商户号

(3)WEB项目:本人的项目基于SpringBoot+SSM框架的网站项目

(4)demo:github链接

第二步生成二维码

(1)在pom.xml引入依赖:

<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.0</version>

</dependency>

(2)编写工具类QrCodeUtils:

package com.meal.util;

import com.google.zxing.BarcodeFormat;

import com.google.zxing.EncodeHintType;

import com.google.zxing.MultiFormatWriter;

import com.mon.BitMatrix;

import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import javax.imageio.ImageIO;

import java.awt.*;

import java.awt.geom.RoundRectangle2D;

import java.awt.image.BufferedImage;

import java.io.File;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.util.Hashtable;

import java.util.Random;

/**

* 工程名:meal

* 包名:com.meal.util

* 文件名:QrCodeUtils.java

* @author lcwen

* @version $Id: QrCodeUtils.java 3月10日 上午11:53:55 $

*/

public class QrCodeUtils {

private static final String CHARSET = "utf-8";

public static final String FORMAT = "JPG";

// 二维码尺寸

private static final int QRCODE_SIZE = 180;

// LOGO宽度

private static final int LOGO_WIDTH = 60;

// LOGO高度

private static final int LOGO_HEIGHT = 60;

/**

* 生成二维码

*

* @param content 二维码内容

* @param logoPath logo地址

* @param needCompress 是否压缩logo

* @return 图片

* @throws Exception

*/

public static BufferedImage createImage(String content, String logoPath, boolean needCompress) throws Exception {

Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();

hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);

hints.put(EncodeHintType.CHARACTER_SET, CHARSET);

hints.put(EncodeHintType.MARGIN, 1);

BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE,

hints);

int width = bitMatrix.getWidth();

int height = bitMatrix.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, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);

}

}

if (logoPath == null || "".equals(logoPath)) {

return image;

}

// 插入图片

QrCodeUtils.insertImage(image, logoPath, needCompress);

return image;

}

/**

* 插入LOGO

*

* @param source 二维码图片

* @param logoPath LOGO图片地址

* @param needCompress 是否压缩

* @throws IOException

*/

private static void insertImage(BufferedImage source, String logoPath, boolean needCompress) throws IOException {

InputStream inputStream = null;

try {

inputStream = FileUtils.getResourceAsStream(logoPath);

Image src = ImageIO.read(inputStream);

int width = src.getWidth(null);

int height = src.getHeight(null);

if (needCompress) { // 压缩LOGO

if (width > LOGO_WIDTH) {

width = LOGO_WIDTH;

}

if (height > LOGO_HEIGHT) {

height = LOGO_HEIGHT;

}

Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);

BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

Graphics g = tag.getGraphics();

g.drawImage(image, 0, 0, null); // 绘制缩小后的图

g.dispose();

src = image;

}

// 插入LOGO

Graphics2D graph = source.createGraphics();

int x = (QRCODE_SIZE - width) / 2;

int y = (QRCODE_SIZE - height) / 2;

graph.drawImage(src, x, y, width, height, null);

Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);

graph.setStroke(new BasicStroke(3f));

graph.draw(shape);

graph.dispose();

} catch (IOException e) {

e.printStackTrace();

throw new RuntimeException(e);

} finally {

if (inputStream != null) {

inputStream.close();

}

}

}

/**

* 生成二维码(内嵌LOGO)

* 二维码文件名随机,文件名可能会有重复

*

* @param content 内容

* @param logoPath LOGO地址

* @param destPath 存放目录

* @param needCompress 是否压缩LOGO

* @throws Exception

*/

public static String encode(String content, String logoPath, String destPath, boolean needCompress) throws Exception {

BufferedImage image = QrCodeUtils.createImage(content, logoPath, needCompress);

mkdirs(destPath);

String fileName = new Random().nextInt(99999999) + "." + FORMAT.toLowerCase();

ImageIO.write(image, FORMAT, new File(destPath + "/" + fileName));

return fileName;

}

/**

* 生成二维码(内嵌LOGO)

* 调用者指定二维码文件名

*

* @param content 内容

* @param logoPath LOGO地址

* @param destPath 存放目录

* @param fileName 二维码文件名

* @param needCompress 是否压缩LOGO

* @throws Exception

*/

public static String encode(String content, String logoPath, String destPath, String fileName, boolean needCompress) throws Exception {

BufferedImage image = QrCodeUtils.createImage(content, logoPath, needCompress);

mkdirs(destPath);

fileName = fileName.substring(0, fileName.indexOf(".") > 0 ? fileName.indexOf(".") : fileName.length())

+ "." + FORMAT.toLowerCase();

ImageIO.write(image, FORMAT, new File(destPath + "/" + fileName));

return fileName;

}

/**

* 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.

* (mkdir如果父目录不存在则会抛出异常)

*

* @param destPath 存放目录

*/

public static void mkdirs(String destPath) {

File file = new File(destPath);

if (!file.exists() && !file.isDirectory()) {

file.mkdirs();

}

}

/**

* 生成二维码(内嵌LOGO)

*

* @param content 内容

* @param logoPath LOGO地址

* @param destPath 存储地址

* @throws Exception

*/

public static String encode(String content, String logoPath, String destPath) throws Exception {

return QrCodeUtils.encode(content, logoPath, destPath, false);

}

/**

* 生成二维码

*

* @param content 内容

* @param destPath 存储地址

* @param needCompress 是否压缩LOGO

* @throws Exception

*/

public static String encode(String content, String destPath, boolean needCompress) throws Exception {

return QrCodeUtils.encode(content, null, destPath, needCompress);

}

/**

* 生成二维码

*

* @param content 内容

* @param destPath 存储地址

* @throws Exception

*/

public static String encode(String content, String destPath) throws Exception {

return QrCodeUtils.encode(content, null, destPath, false);

}

/**

* 生成二维码(内嵌LOGO)

*

* @param content 内容

* @param logoPath LOGO地址

* @param output 输出流

* @param needCompress 是否压缩LOGO

* @throws Exception

*/

public static void encode(String content, String logoPath, OutputStream output, boolean needCompress)

throws Exception {

BufferedImage image = QrCodeUtils.createImage(content, logoPath, needCompress);

ImageIO.write(image, FORMAT, output);

}

/**

* 生成二维码

*

* @param content 内容

* @param output 输出流

* @throws Exception

*/

public static void encode(String content, OutputStream output) throws Exception {

QrCodeUtils.encode(content, null, output, false);

}

}

(3)调用工具类生产二维码(根据各自业务生成对应的二维码,其中二维码路径可用redis缓存并设置过期时间减少二维码频繁生成,过期可重新生成)

第三步:在微信和支付宝开发文档下载对应的SDK DEMO

(1)微信支付宝引入依赖

<!-- 支付宝SDK -->

<dependency>

<groupId>com.alipay.sdk</groupId>

<artifactId>alipay-sdk-java</artifactId>

<version>4.9.5.ALL</version>

</dependency>

<!-- 微信支付SDK -->

<dependency>

<groupId>com.github.wxpay</groupId>

<artifactId>wxpay-sdk</artifactId>

<version>0.0.3</version>

</dependency>

<!-- XML转bean对象 -->

<dependency>

<groupId>com.thoughtworks.xstream</groupId>

<artifactId>xstream</artifactId>

<version>1.4.10</version>

</dependency>

(2)对应的包目录

(3)对应的代码:链接

第四步:扫描进入二维码对应的URL

(1)控制层处理

/**

* 扫描二维码进入控制器处理具体业务逻辑

*/

@GetMapping(value = "****")

public String payh5(@PathVariable String ***) throws Exception{

String userAgent = request.getHeader("user-agent");

if (userAgent == null

|| !(userAgent.contains("AlipayClient") || userAgent

.contains("MicroMessenger"))) {

log.info("未知来源扫码进入付费模块,返回无页面...");

return "****";

}

if (userAgent.contains("AlipayClient")) { //支付宝

Map<String, Object> pay = vipChargeService.findParamForPay(***);//对应需要的参数

request.setAttribute("info", pay.get("info")); //前端H5页面需要的参数

request.setAttribute("payParam", pay.get("payParam"));//支付宝支付需要的参数

return "school/vip/alipay_h5";

}else{

Map<String, Object> pay = vipChargeService.findParamForPay(****);//对应需要的参数

request.setAttribute("appId", pay.get("appId"));//APPID - 公众号APPID

request.setAttribute("url", pay.get("url")); //微信静默授权成功后 跳转到微信支付页面的URL

request.setAttribute("state", pay.get("state"));//微信附加参数

return "**/wx_auth"; //微信授权页面

}

}

/**

* 跳转到微信支付页 ,该处为微信授权成功后回调路径

* @param state 微信返回附加参数

* @param code 授权code

* @return

*/

@GetMapping(value = "/wxpayh5/")

public String getWxpayParam(String state ,String code){

if (StringUtils.isEmpty(state) || StringUtils.isEmpty(code)) {

return "***/expire_h5";//过期页面

}

try {

vipChargeService.findWxPayMwebUrl(request,***, code);

return "***/wxpay_h5";//支付页面

} catch (Exception e) {

log.error("微信获取支付参数出错,错误信息:", e.getMessage(), e);

e.printStackTrace();

}

return "***/expire_h5";//过期页面

}

(2)业务层处理vipChargeService

@Override

public Map<String, Object> findParamForPay(***, int payType) throws Exception {

long time = redisGetService.getOrderExpireTime(***); //获取剩余过期时间单位秒

Date expireTime = new Date(new Date().getTime() + 1000 * time);//获取过期的具体时间

String backParams = ****;//附加参数

Map<String, Object> result = new HashMap<String, Object>();

if (payType == 1) { //微信

WXPayConfig config = new WxpayConfig();

result.put("appId", config.getAppID());

result.put("url", ****);

result.put("state", backParams);

}else { //支付宝

String payParam = AlipayUtil.getPayParam(****);

payParam = payParam.replace("<script>document.forms[0].submit();</script>", "");

result.put("payParam", payParam);

Map<String, Object> info = new HashMap<String, Object>();

//TODO 添加页面需要的参数

result.put("info", info);

}

return result;

}

@Override

public void findWxPayMwebUrl(HttpServletRequest request, ***, String code)

throws Exception {

String openid = WxSignUtil.accessWithOpenid(code);//获取微信用户openid

//TODO 获取相关的参数

long time = redisGetService.getOrderExpireTime(***);

Date expireTime = new Date(new Date().getTime() + 1000 * time);

String ip = *****;//获取客户端IP地址 -> 自己百度

String notify_url = UrlConstants.VIP_NOTIFY_URL;

String attach = "****";//附带参数

Map<String, Object> result = WxPayUtil.getH5PayParam(***, openid);

if (result == null) {

throw new Exception("获取微信订单参数失败");

}

Map<String, Object> info = new HashMap<String, Object>();

//TODO 返回至支付页面需要的参数

request.setAttribute("info", info);

request.setAttribute("result", result);

}

(3)微信的授权页面、微信的支付页面、支付宝的支付页面:链接

第五步:异步通知

(1)支付宝异步通知/同步通知

package com.meal.module.school.api;

import java.math.BigDecimal;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import com.alipay.api.internal.util.AlipaySignature;

import com.meal.constant.UrlRoot;

import com.meal.module.admin.order.service.PcOrderService;

import com.meal.pay.alipay.config.AlipayConfig;

/**

* 文件名:AlipayController.java

* @author lcwen

* @version $Id: AlipayController.java 3月11日 上午11:34:45 $

*/

@Controller

@RequestMapping(value = UrlRoot.ALIPAY_NOTIFY_URL)

public class AlipayController {

private static final Logger log = LoggerFactory.getLogger(AlipayController.class);

@Autowired

private HttpServletRequest request;

@RequestMapping(value = "/notify_url")

public void notify_url(){

try {

boolean signVerified = signVerify(request);

if (!signVerified) {// 是否验证不成功

log.error("支付宝异步通知验证签名失败");

return;

}

String trade_status = new String(request.getParameter(

"trade_status").getBytes("ISO-8859-1"), "UTF-8");

if (!trade_status.equals("TRADE_FINISHED") && !trade_status.equals("TRADE_SUCCESS")) {

log.info("支付宝异步通知回调结果:失败");

return;

}

String out_trade_no = request.getParameter("out_trade_no");

String trade_no = request.getParameter("trade_no");

//TODO处理订单

//**********************

} catch (Exception e) {

log.error("支付宝异步通知出错,错误信息:",e.getMessage(),e);

e.printStackTrace();

}

}

/**

* 简要说明:同步路径 <br>

* 创建者:lcwen

* 创建时间:3月12日 下午5:47:17

* @return

*/

@RequestMapping(value = "/return_url")

public String return_url(){

try {

boolean signVerified = signVerify(request);

if (!signVerified) {

request.setAttribute("msg", "支付失败,签名验证错误!");

return "******"; //支付失败页面

}

return "*****";//支付成功页面

} catch (Exception e) {

request.setAttribute("msg", "支付失败,同步通知出错!");

log.error("支付宝同步通知出错,错误信息:",e.getMessage(),e);

e.printStackTrace();

}

return "*****"; //支付失败页面

}

/**

* 简要说明:支付宝签名验证 <br>

*************************页面功能说明*************************

* 创建该页面文件时,请留心该页面文件中无任何HTML代码及空格。

* 该页面不能在本机电脑测试,请到服务器上做测试。请确保外部可以访问该页面。

* 如果没有收到该页面返回的 success

* 建议该页面只做支付成功的业务逻辑处理,退款的处理请以调用退款查询接口的结果为准。

* 创建者:lcwen

* 创建时间:3月12日 下午5:00:28

* @param request

* @return

* @throws Exception

*/

private boolean signVerify(HttpServletRequest request) throws Exception{

boolean signVerified = false;

// 获取支付宝POST过来反馈信息

Map<String, String> params = new HashMap<String, String>();

Map<String, String[]> requestParams = request.getParameterMap();

for (Iterator<String> iter = requestParams.keySet().iterator(); iter

.hasNext();) {

String name = (String) iter.next();

String[] values = (String[]) requestParams.get(name);

String valueStr = "";

for (int i = 0; i < values.length; i++) {

valueStr = (i == values.length - 1) ? valueStr + values[i]

: valueStr + values[i] + ",";

}

// 乱码解决,这段代码在出现乱码时使用

valueStr = new String(valueStr.getBytes("utf-8"), "utf-8");

params.put(name, valueStr);

}

signVerified = AlipaySignature.rsaCheckV1(params,

AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET,

AlipayConfig.SIGNTYPE); // 调用SDK验证签名

return signVerified;

}

}

(2)微信异步通知

package com.meal.module.school.api;

import java.io.BufferedOutputStream;

import java.io.IOException;

import java.math.BigDecimal;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import com.github.wxpay.sdk.WXPayConfig;

import com.github.wxpay.sdk.WXPayUtil;

import com.meal.constant.UrlRoot;

import com.meal.module.admin.order.service.PcOrderService;

import com.meal.pay.wxpay.config.WxpayConfig;

import com.meal.pay.wxpay.pojo.NotifyInfo;

import com.thoughtworks.xstream.XStream;

import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;

import com.thoughtworks.xstream.io.xml.XppDriver;

/**

* 文件名:WxpayController.java

* @author lcwen

* @version $Id: WxpayController.java 3月11日 上午11:35:02 $

*/

@Controller

@RequestMapping(value = ****)

public class WxpayController {

private static final Logger log = LoggerFactory.getLogger(WxpayController.class);

@Autowired

private HttpServletRequest request;

@Autowired

private HttpServletResponse response;

/**

* 简要说明:异步通知 <br>

* 详细说明:TODO

* 创建者:lcwen

* 创建时间:3月13日 上午10:39:26

* 更新者:

* 更新时间:

*/

@RequestMapping(value = "/notify_url")

public void notify_url() throws Exception{

String notityXml = "";

String inputLine = "";

while ((inputLine = request.getReader().readLine()) != null) {

notityXml += inputLine;

}

request.getReader().close();

WXPayConfig config = new WxpayConfig();

XStream xs = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-",

"_")));

xs.alias("xml", NotifyInfo.class);

NotifyInfo ntfInfo = (NotifyInfo)xs.fromXML(notityXml.toString());

// 验证签名是否正确

boolean isSign = WXPayUtil.isSignatureValid(notityXml, config.getKey());

if(!isSign){

signFail(response);

return;

}

if (!"SUCCESS".equals(ntfInfo.getReturn_code())

|| !"SUCCESS".equals(ntfInfo.getResult_code())) {

payFail(response,ntfInfo.getErr_code());

return;

}

//订单号、微信交易号、

String out_trade_no = ntfInfo.getOut_trade_no();

String trade_no = ntfInfo.getTransaction_id();

//TODO 订单处理

//**************************

payOk(response);

}

/**

* 支付成功

*/

private static void payOk(HttpServletResponse response){

log.info("================ 微信支付异步回调支付成功返回 =================");

String resXml = "<xml><return_code><![CDATA[SUCCESS]]></return_code>"

+ "<return_msg><![CDATA[OK]]></return_msg></xml> ";

flushResponse(response, resXml);

}

/**

* 支付失败

*/

private static void payFail(HttpServletResponse response ,String errCode){

log.info("================ 微信支付异步回调支付失败返回 =================");

String resXml = "<xml><return_code><![CDATA[FAIL]]></return_code>"

+ "<return_msg><![CDATA[" + errCode + "]]></return_msg></xml>";

flushResponse(response, resXml);

}

/**

* 签名失败

*/

private static void signFail(HttpServletResponse response){

log.info("================ 微信支付异步回调签名失败 =================");

String resXml = "<xml><return_code><![CDATA[FAIL]]></return_code>"

+ "<return_msg><![CDATA[签名有误]]></return_msg></xml> ";

flushResponse(response, resXml);

}

private static void flushResponse(HttpServletResponse response ,String resXml){

BufferedOutputStream out = null;

try {

out = new BufferedOutputStream(response.getOutputStream());

out.write(resXml.getBytes("utf-8"));

out.flush();

} catch (Exception e) {

e.printStackTrace();

}finally{

if (out != null) {

try {

out.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

}

第六部:效果(实际项目)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。