当前位置: 首页>前端>正文

java中如何校验支付码的真伪 java实现二维码付款

第一步准备

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

其中公众号需配置

java中如何校验支付码的真伪 java实现二维码付款,java中如何校验支付码的真伪 java实现二维码付款_java,第1张

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

java中如何校验支付码的真伪 java实现二维码付款,java中如何校验支付码的真伪 java实现二维码付款_Image_02,第2张

(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.google.zxing.common.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 2020年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)对应的包目录

  

java中如何校验支付码的真伪 java实现二维码付款,java中如何校验支付码的真伪 java实现二维码付款_java_03,第3张

(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 2020年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
      * 创建时间:2020年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
      * 创建时间:2020年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 2020年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
      * 创建时间:2020年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();
                 }
             }
         }
     }}

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

                   

java中如何校验支付码的真伪 java实现二维码付款,java中如何校验支付码的真伪 java实现二维码付款_java中如何校验支付码的真伪_04,第4张

                                

java中如何校验支付码的真伪 java实现二维码付款,java中如何校验支付码的真伪 java实现二维码付款_java中如何校验支付码的真伪_05,第5张


https://www.xamrdz.com/web/2g81961724.html

相关文章: