项目搭建基于ssm框架,本博客略过搭建过程,记得引入文件上传、zxing、mybatis、mysql依赖包
<!-- https://mvnrepository.com/artifact/com.google.zxing/core -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.3.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.zxing/javase -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.3.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
简述实现原理:
合码中承载后台请求地址和支付信息库中存储id,在支付宝、微信、qq钱包在扫码请求时,会带有识别的UA信息,基于UA分别出何种请求终端,并返回相应的支付信息。也就是说分为两大步骤:合码、解码。
- 合码 解析上传二维码承载的信息,入库储存,返回库主键,与解码请求地址拼接,生成二维码合码
- 解码 甄别请求终端,检索库中支付信息,返回与终端相匹配的支付信息
下面来看代码实现
接收页面上传的收款码二维码,进行解析,解析完毕之后存储入库,并生成带有解码请求地址与库主键的二维码合码
private static final String AlIBABA = "qr.alipay.com";
private static final String WEIXIN = "wxp";
private static final String QQ = "i.qianbao.qq.com";
public String mergeQrCode(Model model, @RequestParam("aliQrcodeImage") CommonsMultipartFile aliQrcodeImage,
@RequestParam("wxQrcodeImage") CommonsMultipartFile wxQrcodeImage,
@RequestParam("qqQrcodeImage") CommonsMultipartFile qqQrcodeImage, HttpServletRequest request)
throws IOException {
String alipayUrl = "";
String wechatUrl = "";
String qqUrl = "";
int nullNum = 0;
if ( null == aliQrcodeImage) {
nullNum++;
} else {
InputStream inputStream = aliQrcodeImage.getInputStream();
String qrcodeContext = QrcodeUtils.decodeQrcode(inputStream);
alipayUrl = qrcodeContext.trim();
qrcodeContext = qrcodeContext.toLowerCase();
if (!qrcodeContext.contains(AlIBABA)) {
alipayUrl = "";
model.addAttribute("status", "99999");
model.addAttribute("msg", "支付宝收款码错误");
return "merge-qrcode";
}
}
if ( null == wxQrcodeImage) {
nullNum++;
} else {
InputStream inputStream = wxQrcodeImage.getInputStream();
String qrcodeContext = QrcodeUtils.decodeQrcode(inputStream);
wechatUrl = qrcodeContext.trim();
qrcodeContext = qrcodeContext.toLowerCase();
if (!qrcodeContext.contains(WEIXIN)) {
wechatUrl = "";
model.addAttribute("status", "99999");
model.addAttribute("msg", "微信收款码错误");
return "merge-qrcode";
}
}
if ( null == qqQrcodeImage) {
nullNum++;
} else {
InputStream inputStream = qqQrcodeImage.getInputStream();
String qrcodeContext = QrcodeUtils.decodeQrcode(inputStream);
qqUrl = qrcodeContext.trim();
qrcodeContext = qrcodeContext.toLowerCase();
if (!qrcodeContext.contains(QQ)) {
qqUrl = "";
model.addAttribute("status", "99999");
model.addAttribute("msg", "QQ钱包收款码错误");
return "merge-qrcode";
}
}
if ((nullNum > 0) || (StringUtils.isEmpty(alipayUrl)) || (StringUtils.isEmpty(wechatUrl))
|| (StringUtils.isEmpty(qqUrl))) {
model.addAttribute("status", "99999");
model.addAttribute("msg", "请上传支付宝、微信、QQ钱包三种收款码");
return "merge-qrcode";
}
List<AllPayInfo> allPayInfoList = new ArrayList<AllPayInfo>();
AllPayInfo allPayInfo = new AllPayInfo();
allPayInfo.setAlipayUrl(alipayUrl);
allPayInfo.setWechatUrl(wechatUrl);
allPayInfo.setQqUrl(qqUrl);
allPayInfoList.add(allPayInfo);
if (this.payInfoService.insert(allPayInfoList) > 0) {
StringBuilder newQrCodeContent = new StringBuilder(request.getScheme());
newQrCodeContent.append("://").append(request.getServerName()).append(":").append(request.getServerPort())
.append(request.getContextPath()).append("/");
newQrCodeContent.append("pay?id=").append(allPayInfo.getId());
String path = generateQrCode(newQrCodeContent.toString());
model.addAttribute("status", "10000");
model.addAttribute("msg", "merge成功");
model.addAttribute("imagePath", path);
return "merge-qrcode";
}
model.addAttribute("status", "99999");
model.addAttribute("msg", "merge失败");
return "merge-qrcode";
}
接收支付宝、微信、qq钱包终端扫码合码之后的请求,甄别终端类型,从库中检索真实收款码信息并返回
public String allpay(Model model, @RequestParam("id") String id, HttpServletRequest request) throws IOException {
if (StringUtils.isEmpty(id)) {
model.addAttribute("status", "99999");
model.addAttribute("msg", "收款码错误");
return "merge-qrcode";
}
AllPayInfo allPayInfo = this.payInfoService.queryById(id);
if (StringUtils.isEmpty(allPayInfo)) {
model.addAttribute("status", "99999");
model.addAttribute("msg", "收款码错误");
return "merge-qrcode";
}
String qqUrl = allPayInfo.getQqUrl();
String wechatUrl = allPayInfo.getWechatUrl();
String alipayUrl = allPayInfo.getAlipayUrl();
String payUrl = "";
String scanType = "0";
String userAgent = request.getHeader("user-agent");
if (null != userAgent) {
userAgent = userAgent.toLowerCase();
if (userAgent.contains("alipayclient")) {
payUrl = alipayUrl;
scanType = "1";
model.addAttribute("payUrl", payUrl);
} else if (userAgent.contains("micromessenger")) {
payUrl = wechatUrl;
scanType = "2";
} else if (userAgent.contains("qq")) {
payUrl = qqUrl;
scanType = "3";
} else {
StringBuilder newQrCodeContent = new StringBuilder(request.getScheme());
newQrCodeContent.append("://").append(request.getServerName()).append(":")
.append(request.getServerPort()).append(request.getContextPath()).append("/");
newQrCodeContent.append("pay?id=").append(id);
payUrl = newQrCodeContent.toString();
}
}
String path = generateQrCode(payUrl);
model.addAttribute("scanType", scanType);
model.addAttribute("imagePath", path);
return "allpay";
}
private String generateQrCode(String content) throws IOException {
String nameId = UUID.randomUUID().toString().replace("-", "");
String path = "/upload/" + nameId + ".png";
String mergeIamge = FileImageUtils.staticFileUploadDir() + path;
File file = new File(mergeIamge);
QrcodeUtils.createQrcodeImage(content, Integer.valueOf(300), file);
return path;
}
其中支付宝与微信、qq钱包的引导方式不一样。
- 支付宝 网页引导即可
- 微信、qq 须引导用户长按识别
<body> <c:if test="${ 0 == scanType}"> <!-- 万能收款码展示区域 --> <div class="code-item show" id="code-all"> <div class="code-title"></div> <div class="code-area"> <img id="pay-url" src="${ctx}/${imagePath}"> </div> <div class="code-footer">扫描以上二维码向我付款</div> </div> </c:if> <c:if test="${ 3 == scanType}"> <!-- QQ钱包二维码展示区域 --> <div class="code-item show" id="code-qq"> <div class="code-title"></div> <div class="code-area"> <img id="pay-url" src="${ctx}/${imagePath}"> </div> <div class="code-footer">长按以上二维码向我付款</div> </div> </c:if> <c:if test="${ 2 == scanType}"> <!-- 微信二维码展示区域 --> <div class="code-item show" id="code-wechat"> <div class="code-title"></div> <div class="code-area"> <img id="pay-url" src="${ctx}/${imagePath}"> </div> <div class="code-footer">长按以上二维码向我付款</div> </div> </c:if> <c:if test="${ 1 == scanType}"> <!-- 支付宝二维码展示区域 --> <div class="code-item" id="code-alipay"> <div class="code-title"></div> <div class="code-area"> <img id="pay-url" scanType="${scanType}" payUrl="${payUrl}" src="${ctx}/${imagePath}"> </div> </div> </c:if> </body> <script type="text/javascript" src="${ctx}/js/jquery-2.2.3.min.js" ></script> <script type="text/javascript"> jQuery(function(){ var $payUrl = $('#pay-url'); var scanType = $payUrl.attr('scanType'); var payUrl = $payUrl.attr('payUrl'); if ("1" == scanType) { // 支付宝 window.location.href = payUrl; } }) </script>
**注意** 部署在外网方可正常使用,否则只能生成聚合码,不能扫
有啥问题希望大家留言,一起学习~