(Java微服务项目)聚合支付二维码管理模块功能实现及聚合二维码预支付流程
(Java微服务项目)聚合支付二维码管理模块功能实现及聚合二维码预支付流程
1 聚合二维码管理-创建二维码流程

运营人员在聚合支付运营系统进入到二维码管理界面,点击创建二维码输入创建二维码的数量,没有选择则默认为系统数量。然后请求创建二维码的后台接口,后台接口接收到请求数据,先生成二维码编号(全系统唯一)再对编号进行base64(用于在网络传输)。组装好二维码的内容信息(提供给用户调用dtpay聚合支付系统授权的外网访问地址),最后系统调用生成二维码的工具组件(google zxing),生成成功后返回成功结果。最后运营人员可以在管理界面对二维码进行批量下载
2 聚合二维码管理-二维码和商户绑定流程

二维码创建好后并不具备聚合支付功能,这时需要商家自行扫上一个流程生成的二维码,跳转到商家小程序进行支付入网,提交相关信息(营业执照,法人身份证及结算信息),dtpay接收到小程序提交的资料 请求支付机构入网接口完成商户入网,入网成功后支付机构返回支付机构商户号,dtpay对二维码、商户号和支付机构商户号进行绑定,完成商家注册并开通聚合支付功能(这是用户扫该二维码可以进行聚合支付),返回信息到小程序注册成功。
3 消费者使用二维码dtpay后台接口代码流程

用户使用支付APP(微信,支付宝,云闪付)扫上一个流程的二维码,这时会跳转到dtpay支付交易系统用户授权接口,当前这个接口会设置好(微信,支付宝,云闪付)支付机构用户授权需要的url和各项参数(如:appid)。设置完成后dtpay跳转到获取(微信,支付宝,云闪付)支付app的userAgent(通过javascript)获取。根据获取到的userAgent跳转到对应的支付平台进行用户授权,授权成功后支付机构会回调在上一步设置好的回调地址并推送授权码,该授权码是用于请求下一个支付机构的接口(该接口用户获取用户的openid和userid)。dtpay交易系统拿到openid或userid后发起预支付,支付机构返回预支付响应参数(如:预支付订单号),dtpay交易系统返回能唤起(微信,支付宝,云闪付)APP支付功能并输入密码的界面。用户完成支付,支付机构通过回调地址推送支付结果给到dtpay支付交易系统
4 二维码管理-批量生成聚合二维码Java代码
4.1 创建二维码入口接口代码实现
package cn.itbeien.api.controller.qrmanager;
import cn.itbeien.api.enums.QREnum;
import cn.itbeien.api.enums.SystemEnum;
import cn.itbeien.api.service.qr.IQrCodeService;
import cn.itbeien.api.util.Base64Util;
import cn.itbeien.api.util.DtUtil;
import cn.itbeien.api.util.zxingqr.QrcodeUtil;
import cn.itbeien.entity.DtQrCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
import java.nio.file.Path;
import java.util.Date;
/**
* @author beien
* @date 2024-04-04 18:45
* Copyright© 2024 beien
* 二维码管理模块
*/
@RestController
@RequestMapping("qrmanager")
@Slf4j
public class QrCodeController {
/**
* 二维码中的内容,域名url
*/
@Value("${system.qrcode.url}")
private String qrCodeUrl;
@Value("${qr.number}")
private Integer number;
@Value("${qrcode_location}")
private String qrLocation;
@Autowired
private IQrCodeService qrCodeService;
/**
* 批量生成二维码
* number 批量生成的数量
*/
@PostMapping("batchCreateQR")
public String batchCreateQR(Integer number){
String result = SystemEnum.ERROR.getMessage();
try{
Integer qrNumber = number == null ? this.number : number;
qrCodeService.saveQR(qrNumber,qrCodeUrl,qrLocation);
result = SystemEnum.SUCCESS.getMessage();
}catch(Exception e){
log.error("创建二维码异常:{}",e);
}
return result;
}
}
4.2 创建二维码服务层代码实现
package cn.itbeien.api.service.qr.impl;
import cn.itbeien.api.dao.DtQrCodeMapper;
import cn.itbeien.api.enums.QREnum;
import cn.itbeien.api.service.qr.IQrCodeService;
import cn.itbeien.api.util.Base64Util;
import cn.itbeien.api.util.DtUtil;
import cn.itbeien.api.util.zxingqr.QrcodeUtil;
import cn.itbeien.entity.DtQrCode;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.File;
import java.nio.file.Path;
import java.util.Date;
/**
* @author beien
* @date 2024-04-04 20:24
* Copyright© 2024 beien
*/
@Service
public class QrCodeService implements IQrCodeService {
@Resource
private DtQrCodeMapper dtQrCodeMapper;
/**
*
* @param qrNumber 创建聚合二维码的数量
* @param qrCodeUrl 聚合二维码中的内容
* @param qrLocation 聚合二维码存放的物理路径
* @return
* @throws Exception
*/
@Override
public void saveQR(Integer qrNumber,String qrCodeUrl,String baseQrLocation) throws Exception{
for(int i=0;i<qrNumber;i++){//批量创建聚合二维码
String qrCode = DtUtil.uuid();
String qrCodeBase64 = Base64Util.encodeBase64(qrCode.getBytes());
//二维码内容为域名地址+base64的二维码编号
//system.qrcode.url=http://外网域名/pay/auth?code=%s
String content = String.format(qrCodeUrl,qrCodeBase64);
//qrcode_location=D:\dtpay\qrimg\%s
String qrLocation = String.format(baseQrLocation,qrCode+".png");
Path file = new File(qrLocation).toPath();
QrcodeUtil.createQr(content,file);
DtQrCode dtQrCode = new DtQrCode();
dtQrCode.setQrCode(qrCode);
dtQrCode.setQrStatus(QREnum.STATUS_ENABLE.getCode());
dtQrCode.setCreateBy(Long.parseLong(QREnum.SYSTEM.getCode()));
dtQrCode.setCreateUser(QREnum.SYSTEM.getName());
dtQrCode.setCreateTime(new Date());
dtQrCode.setQrUrl(qrLocation);
dtQrCodeMapper.insertSelective(dtQrCode);
}
}
}
4.3 相关工具类代码实现
package cn.itbeien.api.util.zxingqr;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import lombok.extern.slf4j.Slf4j;
import java.awt.*;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
/**
* @author beien
* @date 2024-03-12 11:02
* Copyright© 2024 beien
*/
@Slf4j
public class QrcodeUtil {
private final static String FILE_FORMAT = "png";
/**
* 输出到指定路径
*/
public static void createQrCodeToPath(BitMatrix bitMatrix, Path path) throws IOException {
MatrixToImageWriter.writeToPath(bitMatrix, FILE_FORMAT, path);
log.info("createQrCodeToPath ok...");
}
/**
* 输出到指定路径
*/
public static void createQrCodeToPath(BitMatrix bitMatrix, Path path, Color front,Color background) throws IOException {
MatrixToImageConfig config = new MatrixToImageConfig(front.getRGB(), background.getRGB());
MatrixToImageWriter.writeToPath(bitMatrix, FILE_FORMAT, path,config);
log.info("createQrCodeToPath ok...");
}
/**
* 输出到流
*/
public static void createQrCodeToStream(BitMatrix bitMatrix, OutputStream stream) throws IOException {
MatrixToImageWriter.writeToStream(bitMatrix, FILE_FORMAT, stream);
log.info("createQrCodeTo ok...");
}
/**
* 输出到流
*/
public static void createQrCodeToStream(BitMatrix bitMatrix, OutputStream stream,Color front,Color background) throws IOException {
MatrixToImageConfig config = new MatrixToImageConfig(front.getRGB(), background.getRGB());
MatrixToImageWriter.writeToStream(bitMatrix, FILE_FORMAT, stream,config);
log.info("createQrCodeTo ok...");
}
/**
* 创建附带本地路径的logo的二维码,到指定路径
* @throws IOException
*/
public static void createLogoQrCodeToPath(BitMatrix bitMatrix,Path codePath,Path logoPath)throws IOException{
MatrixToImageWriterWithLogo.writeToPath(bitMatrix,FILE_FORMAT,codePath,logoPath);
}
/**
* 创建附带url路径的logo的二维码,到指定路径
* @throws IOException
*/
public static void createLogoQrCodeToPath(BitMatrix bitMatrix, Path codePath, URL logoUrl)throws IOException{
MatrixToImageWriterWithLogo.writeToPath(bitMatrix,FILE_FORMAT,codePath,logoUrl);
}
/**
* 创建附带本地路径的logo的二维码,到输出流
*/
public static void createLogoQrCodeToStream(BitMatrix bitMatrix,OutputStream os,Path logoPath)throws IOException{
MatrixToImageWriterWithLogo.writeToStream(bitMatrix,FILE_FORMAT,os,logoPath);
}
/**
* 创建附带本地路径的logo的二维码,到指定路径
*/
public static void createLogoQrCodeToPath(BitMatrix bitMatrix,Path codePath,Path logoPath,Color front,Color background)throws IOException{
MatrixToImageConfig config = new MatrixToImageConfig(front.getRGB(), background.getRGB());
MatrixToImageWriterWithLogo.writeToPath(bitMatrix,FILE_FORMAT,codePath,logoPath,config);
}
/**
* 创建附带url路径的logo的二维码,到指定路径
*/
public static void createLogoQrCodeToPath(BitMatrix bitMatrix, Path codePath, URL logoUrl, Color front, Color background)throws IOException{
MatrixToImageConfig config = new MatrixToImageConfig(front.getRGB(), background.getRGB());
MatrixToImageWriterWithLogo.writeToPath(bitMatrix,FILE_FORMAT,codePath,logoUrl,config);
}
/**
* 创建附带本地路径的logo的二维码,到输出流
*/
public static void createLogoQrCodeToStream(BitMatrix bitMatrix,OutputStream os,Path logoPath,Color front,Color background)throws IOException{
MatrixToImageConfig config = new MatrixToImageConfig(front.getRGB(), background.getRGB());
MatrixToImageWriterWithLogo.writeToStream(bitMatrix,FILE_FORMAT,os,logoPath,config);
}
/**
*
* @param content 二维码中的内容
* @param file 图片存储的磁盘路径
* http://www.itbeien.net
* 对应的是注册商户,跳转支付H5页面的controller中方法的地址
* (域名或者IP需要能外网访问)
* http://itbeien.vicp.fun/system/route?code=10001
*
*
*/
public static void createQr(String content,Path file){
int width=500;
int height=500;
String format ="png";
//定义二维码参数
Map hashMap = new HashMap();
hashMap.put(EncodeHintType.CHARACTER_SET,"UTF-8");
hashMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
hashMap.put(EncodeHintType.MARGIN,2);
try {
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE,width,height);
MatrixToImageWriter.writeToPath(bitMatrix,format,file);
}catch (Exception e){
log.error("创建二维码异常:",e);
}
}
/**
* 批量创建二维码
* @param content 二维码中的内容
* @param file 图片存储的磁盘路径
* http://itbeien.vicp.fun/system/route?code=10001
* 对应的是注册商户,跳转支付H5页面的controller中方法的地址
* (域名或者IP需要能外网访问)
* http://itbeien.vicp.fun/system/route?code=10001
*
*
*/
public static void createBatchQr(String content,Path file,Integer number){
int width=500;
int height=500;
String format ="png";
//定义二维码参数
Map hashMap = new HashMap();
hashMap.put(EncodeHintType.CHARACTER_SET,"UTF-8");
hashMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
hashMap.put(EncodeHintType.MARGIN,2);
try {
for(int i=0;i<number;i++){
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE,width,height);
MatrixToImageWriter.writeToPath(bitMatrix,format,file);
}
}catch (Exception e){
log.error("创建二维码异常:",e);
}
}
}
4.4 pom.xml 依赖配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.itbeien</groupId>
<artifactId>dtpay</artifactId>
<version>2.0.0</version>
</parent>
<artifactId>dtpay-api</artifactId>
<dependencies>
<!-- Mysql驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<!-- 阿里JSON解析器 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.12</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.12</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.47</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>20030203.000129</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>aliyun-sms-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.39.2.ALL</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.5.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
</dependencies>
</project>
5 相关数据表设计
二维码和二维码商户中间表

商户信息表信息太多,只截取了少部分字段

加入我的星球
加入知识星球,参与项目讨论,在星球内置顶内容可以找到我微信联系方式,添加微信请备注星球会员没有备注的同学不理会。
