Java 实现微信和支付宝支付功能

作者:fangzhihua0927 时间:2023-03-08 23:18:04 

一、前期准备

1、申请好微信商户号appid,拿到商户id和商户秘钥,退款的话需要商户证书
2、申请好支付宝商户号appid,商户公钥和秘钥(需要用支付宝工具自己生成),支付宝退款不需要证书

二、数据库表设计

1、微信支付配置表


CREATE TABLE `py_wx_config` (
`wx_config_id` varchar(18) NOT NULL COMMENT '微信支付配置ID',
`appid` varchar(128) DEFAULT NULL COMMENT '微信公众号ID',
`mch_id` varchar(128) DEFAULT NULL COMMENT '商户号ID',
`mch_key_secret` varchar(2200) DEFAULT NULL COMMENT '商户安全密钥',
`crt_path` varchar(200) DEFAULT NULL COMMENT '商户证书存放路径',
`app_secret` varchar(2200) DEFAULT NULL COMMENT '公众号安全密钥',
`create_id` varchar(18) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`upd_id` varchar(18) DEFAULT NULL COMMENT '修改人',
`upd_time` datetime DEFAULT NULL COMMENT '修改时间',
`delete_flag` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标志',
`app_code` varchar(18) NOT NULL COMMENT '商家编码',
`bm_code` varchar(20) DEFAULT NULL COMMENT '部门编码',
PRIMARY KEY (`wx_config_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='微信支付配置';

2、微信小程序支付配置表


CREATE TABLE `py_wx_min_config` (
`wx_min_config_id` varchar(18) NOT NULL COMMENT '微信支付配置ID',
`appid` varchar(128) DEFAULT NULL COMMENT '微信公众号ID',
`mch_id` varchar(128) DEFAULT NULL COMMENT '商户号ID',
`mch_key_secret` varchar(2200) DEFAULT NULL COMMENT '商户安全密钥',
`crt_path` varchar(200) DEFAULT NULL COMMENT '商户证书存放路径',
`app_secret` varchar(2200) DEFAULT NULL COMMENT '公众号安全密钥',
`create_id` varchar(18) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`upd_id` varchar(18) DEFAULT NULL COMMENT '修改人',
`upd_time` datetime DEFAULT NULL COMMENT '修改时间',
`delete_flag` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标志',
`app_code` varchar(18) NOT NULL COMMENT '商家编码',
`sys_software_code` varchar(18) DEFAULT NULL COMMENT '系统编码',
PRIMARY KEY (`wx_min_config_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='微信支付配置';

3、支付宝支付配置表


CREATE TABLE `py_alipay_config` (
`alipay_config_id` varchar(18) NOT NULL COMMENT '支付宝支付配置ID',
`ali_private_key` varchar(2200) DEFAULT NULL COMMENT '支付宝密钥',
`ali_public_key` varchar(2200) DEFAULT NULL COMMENT '支付宝公钥',
`ali_appid` varchar(128) DEFAULT NULL COMMENT '支付宝appid',
`create_id` varchar(18) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`upd_id` varchar(18) DEFAULT NULL COMMENT '修改人',
`upd_time` datetime DEFAULT NULL COMMENT '修改时间',
`delete_flag` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标志',
`app_code` varchar(18) NOT NULL COMMENT '商家编码',
PRIMARY KEY (`alipay_config_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='支付宝支付配置';

4、支付流水记录表


CREATE TABLE `py_pay_log` (
`pay_log_id` varchar(18) NOT NULL COMMENT '支付流水ID',
`pay_no` varchar(20) DEFAULT NULL COMMENT '支付订单号',
`third_id` varchar(64) DEFAULT NULL COMMENT '微信支付宝订单ID',
`money_type` varchar(20) DEFAULT NULL COMMENT '支付类型 0-微信 1-支付宝 2-会员卡 3-银联',
`mq_topic` varchar(100) DEFAULT NULL COMMENT 'MQ主题',
`mq_status` tinyint(3) DEFAULT NULL COMMENT 'MQ发送状态 0-待发送 1-已发送 2-发送失败',
`mq_remark` varchar(100) DEFAULT NULL COMMENT 'MQ发送备注',
`request` text COMMENT '发送数据',
`response` text COMMENT '返回数据',
`fee` decimal(14,2) DEFAULT NULL COMMENT '订单金额',
`create_id` varchar(18) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`upd_id` varchar(18) DEFAULT NULL COMMENT '修改人',
`upd_time` datetime DEFAULT NULL COMMENT '修改时间',
`delete_flag` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标志',
`app_code` varchar(18) NOT NULL COMMENT '商家编码',
`pay_config_json_str` longtext COMMENT '支付配置',
PRIMARY KEY (`pay_log_id`) USING BTREE
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='支付流水';

5、支付失败记录表


CREATE TABLE `pay_fail_log` (
`pay_id` varchar(18) NOT NULL,
`json_date` varchar(500) DEFAULT NULL,
`create_id` varchar(18) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_id` varchar(18) DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
`app_code` varchar(18) NOT NULL,
`delete_flag` tinyint(1) DEFAULT '0' COMMENT '是否删除:0-否;1-是',
PRIMARY KEY (`pay_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT;

三、依赖引入


<?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">

<parent>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-parent</artifactId>
 <version>2.1.3.RELEASE</version>
 <relativePath/> <!-- lookup parent from repository -->
</parent>

<modelVersion>4.0.0</modelVersion>
<groupId>com.pay</groupId>
<artifactId>qc-payment</artifactId>
<version>2.3</version>
<name>qc-payment</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>

<properties>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 <maven.compiler.source>1.7</maven.compiler.source>
 <maven.compiler.target>1.7</maven.compiler.target>
 <spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>

<dependencies>
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
 </dependency>
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
 </dependency>
 <dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
 </dependency>

<!--z支付宝-->
 <dependency>
  <groupId>com.alipay.sdk</groupId>
  <artifactId>alipay-sdk-java</artifactId>
  <version>3.3.4.ALL</version>
 </dependency>

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <scope>test</scope>
 </dependency>

<!--导入重试机制的坐标-->
 <dependency>
  <groupId>org.springframework.retry</groupId>
  <artifactId>spring-retry</artifactId>
 </dependency>

<!--引入Hystrix依赖-->
 <dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
 </dependency>

<!--导入jwt相关依赖-->
 <dependency>
  <groupId>com.auth0</groupId>
  <artifactId>java-jwt</artifactId>
  <version>3.4.1</version>
 </dependency>

<!-- StringUtil 类-->
 <dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-lang3</artifactId>
  <version>3.3.2</version>
 </dependency>

<!-- ali 连接池 -->
 <dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.1.12</version>
 </dependency>

<!-- mybatis -->
 <dependency>
  <groupId>org.mybatis.spring.boot</groupId>
  <artifactId>mybatis-spring-boot-starter</artifactId>
  <version>2.0.0</version>
 </dependency>

<!-- mysql -->
 <dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
 </dependency>
 <dependency>
  <groupId>javax.persistence</groupId>
  <artifactId>persistence-api</artifactId>
  <version>1.0.2</version>
 </dependency>
 <!-- https://mvnrepository.com/artifact/tk.mybatis/mapper -->
 <dependency>
  <groupId>tk.mybatis</groupId>
  <artifactId>mapper</artifactId>
  <version>4.0.3</version>
 </dependency>

<!-- import lombok 可以省去getter setter toString等方法 -->
 <dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <scope>provided</scope>
 </dependency>

<!-- commons-io -->
 <dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.4</version>
 </dependency>

<!-- 引入easyqinyu-tools项目 -->
 <dependency>
  <groupId>com.pay</groupId>
  <artifactId>easyqinyu-tools</artifactId>
  <version>0.0.1-SNAPSHOT</version>
 </dependency>

<!-- pagehelper分页插件 -->
 <dependency>
  <groupId>com.github.pagehelper</groupId>
  <artifactId>pagehelper</artifactId>
  <version>5.1.2</version>
 </dependency>

<dependency>
  <groupId>com.github.pagehelper</groupId>
  <artifactId>pagehelper-spring-boot-autoconfigure</artifactId>
  <version>1.2.3</version>
 </dependency>
 <dependency>
  <groupId>com.github.pagehelper</groupId>
  <artifactId>pagehelper-spring-boot-starter</artifactId>
  <version>1.2.3</version>
 </dependency>
 <dependency>
  <groupId>com.qcsoft</groupId>
  <artifactId>qc-swagger-ui</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <scope>compile</scope>
 </dependency>
 <dependency>
  <groupId>com.google.zxing</groupId>
  <artifactId>core</artifactId>
  <version>3.3.0</version>
 </dependency>

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>RELEASE</version>
  <scope>compile</scope>
 </dependency>

<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpclient</artifactId>
  <version>${httpclient.version}</version>
 </dependency>

<dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>2.8.2</version>
 </dependency>

<!--阿里云信息发送-->
 <dependency>
  <groupId>com.aliyun</groupId>
  <artifactId>aliyun-java-sdk-core</artifactId>
  <version>3.3.1</version>
 </dependency>
 <dependency>
  <groupId>com.github.1991wangliang</groupId>
  <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
  <version>1.0.0</version>
 </dependency>

<dependency>
  <groupId>org.springframework.kafka</groupId>
  <artifactId>spring-kafka</artifactId>
 </dependency>

<!-- xml解析-->
 <dependency>
  <groupId>com.thoughtworks.xstream</groupId>
  <artifactId>xstream</artifactId>
  <version>1.4.10</version>
 </dependency>

<!-- dom4j -->
 <dependency>
  <groupId>org.dom4j</groupId>
  <artifactId>dom4j</artifactId>
  <version>2.1.1</version>
 </dependency>

<dependency>
  <groupId>com.github.binarywang</groupId>
  <artifactId>weixin-java-common</artifactId>
  <version>3.3.4.B</version>
 </dependency>

<dependency>
  <groupId>org.jodd</groupId>
  <artifactId>jodd-http</artifactId>
  <scope>compile</scope>
 </dependency>

<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-lang3</artifactId>
 </dependency>

<!-- xml解析-->
 <dependency>
  <groupId>commons-beanutils</groupId>
  <artifactId>commons-beanutils</artifactId>
  <version>1.9.3</version>
 </dependency>

<dependency>
  <groupId>jdom</groupId>
  <artifactId>jdom</artifactId>
  <version>1.0</version>
 </dependency>

<dependency>
  <groupId>org.bouncycastle</groupId>
  <artifactId>bcpkix-jdk15on</artifactId>
  <version>1.59</version>
 </dependency>
 <dependency>
  <groupId>org.jodd</groupId>
  <artifactId>jodd-http</artifactId>
  <version>3.7.1</version>
 </dependency>
 <!--二维码工具-->
 <dependency>
  <groupId>com.google.zxing</groupId>
  <artifactId>core</artifactId>
  <version>3.2.1</version>
 </dependency>

<dependency>
  <groupId>com.qcsoft</groupId>
  <artifactId>qc-commonbean</artifactId>
  <version>0.0.1-SNAPSHOT</version>
 </dependency>

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-openfeign</artifactId>
 </dependency>
 <!-- xxl-job-core -->
 <dependency>
  <groupId>com.xuxueli</groupId>
  <artifactId>xxl-job-core</artifactId>
  <version>2.0.1</version>
 </dependency>
 <!--线路跟踪-->
 <dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
 </dependency>

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
 </dependency>
</dependencies>

<dependencyManagement>
 <dependencies>
  <dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-dependencies</artifactId>
   <version>${spring-cloud.version}</version>
   <type>pom</type>
   <scope>import</scope>
  </dependency>
 </dependencies>
</dependencyManagement>
<build>
 <finalName>qc-payment</finalName>
 <plugins>
  <plugin>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-maven-plugin</artifactId>
  </plugin>
  <plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-compiler-plugin</artifactId>
   <configuration>
    <source>8</source>
    <target>8</target>
   </configuration>
  </plugin>
 </plugins>
</build>
</project>

四、程序实现

1、Controller


package com.qcsoft.payment.controller;

import com.alibaba.fastjson.JSON;
import com.qcsoft.commonbean.bean.common.SwaggerConstant;
import com.qcsoft.commonbean.bean.payment.common.PrePayResult;
import com.qcsoft.commonbean.bean.payment.wx.bean.PreOrderParam;
import com.qcsoft.commonbean.bean.payment.wx.exception.WxPayException;
import com.qcsoft.commonbean.bean.payment.wx.util.QrcodeUtils;
import com.qcsoft.easyqinyutools.message.ReturnMsg;
import com.qcsoft.payment.controller.commom.BaseController;
import com.qcsoft.payment.service.PayService;
import com.qcsoft.swaggerui.anno.ApiTag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;

/**
* @Description: 支付控制中心
* @Author:
* @Date:
*/
@RestController
@RequestMapping("/v2")
public class PayController extends BaseController {
private static final Logger logger = LoggerFactory.getLogger(PayController.class);

@Autowired
private PayService payService;

//private final AtomicInteger tick = new AtomicInteger();

/**
 * 统一预支付接口(统一下单)
 *
 * @param orderParam {dh:订单号,payType:支付方式(WXPAY、ALIPAY、MEMBER_CARD、ACCOUNT),appCode:商家编码,
 *     tradeType:支付方式类型(NATIVE、JSAPI、APP、MWEB),openId:支付方式为JSAPI必传,reqId:请求的真实IP地址
 *     ,redirectUrl:支付成功返回地址,appCode:商家编码,outTradeNo:商务订单号,timeExpire,订单到期时间
 *     ,totalAmount:订单金额,body:商品简单描述,subject:订单标题,quitUrl:中途退出}
 * @param token  token
 * @return (微信公众号 / 小程序返回一串json字符串 : { appId :, timeStamp :, nonceStr : , info_package :, paySign :, signType : }, 前端使用微信sdk调用微信支付)
 * (微信扫码支付返回一个连接,前端需要把连接生成一个二维码使用,连接如:weixin://123.123.com/***)
 * (微信H5--返回一个连接,前端需要把连接生成一个连接前端直接跳转该连接使用,使用如:location.href='weixin://123.123.com/***')
 * (支付宝扫码支付--返回一个连接,前端直接跳转到该连接使用,使用如:location.href='weixin://123.123.com/***')
 * (支付宝扫码H5--返回一个页面form表单,前端需要把这个form表单渲染到h5页面上,使用如:$("#view).html(alipayForm)')
 * (支付宝app支付--返回一个参数包,如sdk-version=**&service=**&&service=**&&body=**&&out_trade_no=**&,前端使用支付宝sdk调用app支付')
 * {
 * wxNativeUrl:微信扫码地址
 * wxAppPackage:app支付sdk参数包
 * wxJsapiPackage:公众号支付包
 * wxH5Url:h5支付url
 * wxScanUrl:wxScanUrl
 * alipayScanUrl:支付宝扫码支付url
 * alipayH5Form:支付宝h5支付表单
 * alipayAppParamStr:支付宝app支付参数支付串
 * }
 * @throws WxPayException
 */
@RequestMapping(value = "/prePayOrder")
@ApiTag(SwaggerConstant.PAYMENT_001)
public ReturnMsg prePayOrder(@RequestBody PreOrderParam orderParam) {
 String metadata = JSON.toJSONString(orderParam);
 logger.info("PayController.prePayOrder----\n正在请求支付....,参数为>>>>{}", metadata);
 ReturnMsg ret = new ReturnMsg();
 //预下单
 PrePayResult prePayResult = this.payService.payPreOrder(orderParam);
 ret.setData(prePayResult);
 return ret.success("下单成功,订单有效期为" + orderParam.getTimeExpire());
}

/**
 * 生成支付二维码
 *
 * @param url 二维码地址
 * @throws IOException
 */
@RequestMapping(value = "/createQrCode/url")
@ApiTag(SwaggerConstant.PAYMENT_001)
public void createQrCode(@PathVariable String url, HttpServletRequest request, HttpServletResponse response) throws IOException {
 String queryString = request.getQueryString();
 BufferedImage bufferedImage = QrcodeUtils.encode(url+queryString, 500, 500, null, null);
 BufferedImage grayImage = QrcodeUtils.grayImage(bufferedImage);
 ImageIO.write(grayImage, "png", response.getOutputStream());
}

}

2、PayService


package com.qcsoft.payment.service.impl;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayClient;
import com.qcsoft.commonbean.bean.common.KafkaConstant;
import com.qcsoft.commonbean.bean.payment.ChinaumsConfig;
import com.qcsoft.commonbean.bean.payment.PayLog;
import com.qcsoft.commonbean.bean.payment.common.PayConstant;
import com.qcsoft.commonbean.bean.payment.common.PrePayResult;
import com.qcsoft.commonbean.bean.payment.common.WxPrePayResultPackage;
import com.qcsoft.commonbean.bean.payment.wx.bean.PreOrderParam;
import com.qcsoft.commonbean.bean.payment.wx.bean.request.WxPayUnifiedOrderRequest;
import com.qcsoft.commonbean.bean.payment.wx.bean.result.WxPayUnifiedOrderResult;
import com.qcsoft.commonbean.bean.payment.wx.config.WxPayConfig;
import com.qcsoft.easyqinyutools.utils.JsonUtil;
import com.qcsoft.payment.commns.exception.BaseException;
import com.qcsoft.payment.commns.exception.QYError;
import com.qcsoft.payment.commns.utils.UserUtil;
import com.qcsoft.payment.commns.utils.weixin.PackageUtil;
import com.qcsoft.payment.service.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.SortedMap;
import java.util.TreeMap;

@Service
public class PayServiceImpl implements PayService {
public Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private AliPayService aliPayService;
@Autowired
private WxPayService wxPayService;
@Autowired
private ChinaumsPayService chinaumsPayService;

@Autowired
private UserUtil userUtil;
@Autowired
private PayLogService payLogService;

@Override
public PrePayResult payPreOrder(PreOrderParam orderParam) throws BaseException {
 logger.info("PayServiceImpl.payPreOrder---->>>>\n准备下单.....,当前用户订单号[{}]", orderParam.getDh());
 String temp = "";
 PrePayResult payResult = new PrePayResult();
 //校验支付方式
 String payType = orderParam.getPayType();
 if (!StringUtils.isNotBlank(payType))
  throw new BaseException(QYError.msg("请选择支付方式!"));
 if (PayConstant.WXPAY.toString().equals(payType)) {
  //查询商家配置信息
  WxPayConfig config;
  if (orderParam.getTradeType().equals(PayConstant.WECHATAPP.toString())) {
   config = wxPayService.getWxMinPayConfigByAppCode(orderParam.getAppCode(), orderParam.getSysSoftwareCode());
  } else {
   config = wxPayService.getWxPayConfigByAppCode(orderParam.getAppCode(), orderParam.getBmCode());
  }
  //设置预支付请求参数
  if (orderParam.getTradeType().equals(PayConstant.WECHATAPP.toString())) {
   orderParam.setTradeType(PayConstant.JSAPI.toString());
  }
  WxPayUnifiedOrderRequest requestParam = wxPayService.packRequestParam(orderParam);
  //开始请求预支付接口
  WxPayUnifiedOrderResult result = wxPayService.wxPrePay(config, requestParam);
  //根据支付类型设置值
  WxPrePayResultPackage resultPackage = null;
  if (orderParam.getTradeType().equals(PayConstant.APP.toString()) || orderParam.getTradeType().equals(PayConstant.JSAPI.toString()) || orderParam.getTradeType().equals(PayConstant.WECHATAPP.toString())) {
   resultPackage = new WxPrePayResultPackage();
   String timeMillis = PackageUtil.getTimeStamp();
   String nonceString = PackageUtil.getNonceStr();
   resultPackage.setAppId(result.getAppid());
   resultPackage.setNonceStr(nonceString);
   resultPackage.setTimeStamp(timeMillis);
   resultPackage.setPrePayId(result.getPrepayId());
   resultPackage.setInfoPackage("prepay_id=" + result.getPrepayId());
   resultPackage.setSignType(requestParam.getSignType());
   if (orderParam.getTradeType().equals(PayConstant.APP.toString())) {
    SortedMap<String, String> returnData = PackageUtil.getReturnData(resultPackage, config.getMchId());
    String paysign = PackageUtil.createSign(returnData, config.getMchKey());
    resultPackage.setPaySign(paysign);
    resultPackage.setInfoPackage(returnData.get("package"));
    payResult.setWxAppPackage(resultPackage);
   } else {
    SortedMap<String, String> paypackageParams = new TreeMap<String, String>();
    paypackageParams.put("appId", result.getAppid()); // appid
    paypackageParams.put("timeStamp", timeMillis); //
    paypackageParams.put("nonceStr", nonceString); //
    paypackageParams.put("package", resultPackage.getInfoPackage()); //
    paypackageParams.put("signType", resultPackage.getSignType());
    String paysign = PackageUtil.createSign(paypackageParams, config.getMchKey());
    resultPackage.setPaySign(paysign);
    payResult.setWxJsapiPackage(resultPackage);
   }
  } else if (orderParam.getTradeType().equals(PayConstant.MWEB.toString())) {
   payResult.setWxH5Url(result.getMwebUrl() + " &redirect_url=" + orderParam.getRedirectUrl());
  } else if (orderParam.getTradeType().equals(PayConstant.NATIVE.toString())) {
   payResult.setWxNativeUrl(result.getCodeURL());
  }
  //添加支付日志
  insertPayLog(orderParam, KafkaConstant.PAYMENT_NOTIFY_001.getTopic(), "0", resultPackage, JSON.toJSONString(config));
  return payResult;
 } else if (PayConstant.ALIPAY.toString().equals(payType)) {
  AlipayClient client = aliPayService.getAlipayClientByAppCode(orderParam.getAppCode());
  if (orderParam.getTradeType().equals(PayConstant.APP.toString())) {
   temp = aliPayService.aliAppPay(client, orderParam);
   payResult.setAlipayAppParamStr(temp);
  } else if (orderParam.getTradeType().equals(PayConstant.MWEB.toString())) {
   temp = aliPayService.aliH5Pay(client, orderParam);
   payResult.setAlipayH5Form(temp);
  } else if (orderParam.getTradeType().equals(PayConstant.NATIVE.toString())) {
   temp = aliPayService.aliScanPay(client, orderParam);
   payResult.setAlipayScanUrl(temp);
  }
  //添加支付日志
  insertPayLog(orderParam, KafkaConstant.PAYMENT_NOTIFY_001.getTopic(), "1", orderParam, JSON.toJSONString(aliPayService.getConfigByAppCode(orderParam.getAppCode())));
  return payResult;
 } else if (PayConstant.WECHATAPP.toString().equals(payType)) {

} else if (PayConstant.CHINAUMS.toString().equals(payType)) { //银联pos支付
  //查询商家配置信息
  ChinaumsConfig config;
  config = chinaumsPayService.getPayConfigByAppCode(orderParam.getAppCode(), orderParam.getBmCode());
  if (orderParam.getTradeType().equals(PayConstant.CODE_SCAN.toString())) {
   chinaumsPayService.codeScanPay(config, orderParam);
  }
  //添加支付日志
  insertPayLog(orderParam, KafkaConstant.PAYMENT_NOTIFY_001.getTopic(), "3", orderParam, JSON.toJSONString(config));
  return payResult;
 }
 logger.warn("用户未选择正确的支付方式");
 throw new BaseException(QYError.msg("请选择正确的支付方式!"));

}

public void insertPayLog(PreOrderParam orderParam, String topic, String moneyType, Object obj, String payConfigJsonStr) {
 PayLog payLog = new PayLog();
 payLog.setAppCode(orderParam.getAppCode());
 payLog.setPayLogId(orderParam.getDh());
 payLog.setMoneyType(moneyType);
 payLog.setMqTopic(topic);
 payLog.setMqStatus(0);
 payLog.setPayNo(orderParam.getDh());
 payLog.setRequest(JsonUtil.toJSon(obj));
 payLog.setFee(orderParam.getTotalAmount());
 payLog.setPayConfigJsonStr(payConfigJsonStr);
 payLogService.saveOrUpdate(payLog);
}
}

3、AliPayService


package com.qcsoft.payment.service;

import com.alipay.api.AlipayClient;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.qcsoft.commonbean.bean.payment.AlipayConfig;
import com.qcsoft.commonbean.bean.payment.alipay.AliPayRefundParam;
import com.qcsoft.commonbean.bean.payment.common.PayNotify;
import com.qcsoft.commonbean.bean.payment.wx.bean.PreOrderParam;
import com.qcsoft.easyqinyutools.message.ReturnMsg;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

public interface AliPayService {
/**
 *
 * @param alipayClient
 * @param orderParam
 * @param
 * @return
 */
String aliAppPay(AlipayClient alipayClient,PreOrderParam orderParam);

String aliScanPay(AlipayClient alipayClient, PreOrderParam orderParam);

String aliH5Pay(AlipayClient alipayClient, PreOrderParam orderParam);

void aliPayNotify(PayNotify params);

boolean rsaCheckV1(HttpServletRequest request,String appCode);

AlipayTradeQueryResponse aliPayOrderQuery(AlipayClient alipayClient, String out_trade_no);

AlipayClient getAlipayClientByAppCode(String appCode);

AlipayConfig getConfigByAppCode(String appCode);

/**
 * 支付宝退款接口
 * @param aliPayRefundParam
 * @return
 */
ReturnMsg aliPayRefund(AliPayRefundParam aliPayRefundParam);

}

AliPayServiceImpl


package com.qcsoft.payment.service.impl;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import com.qcsoft.commonbean.bean.payment.AlipayConfig;
import com.qcsoft.commonbean.bean.payment.alipay.AliPayRefundParam;
import com.qcsoft.commonbean.bean.payment.common.PayConstant;
import com.qcsoft.commonbean.bean.payment.common.PayNotify;
import com.qcsoft.commonbean.bean.payment.wx.bean.PreOrderParam;
import com.qcsoft.easyqinyutools.message.ReturnMsg;
import com.qcsoft.payment.commns.exception.BaseException;
import com.qcsoft.payment.commns.exception.QYError;
import com.qcsoft.payment.commns.utils.DateUtils;
import com.qcsoft.payment.commns.utils.RedisUtil;
import com.qcsoft.payment.service.AliPayService;
import com.qcsoft.payment.service.AlipayConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
* 支付宝相关业务实现类
*/
@Service
public class AliPayServiceImpl implements AliPayService {
private static final Logger logger = LoggerFactory.getLogger(AliPayServiceImpl.class);
@Autowired
private AlipayConfigService alipayConfigService;
@Autowired
private RedisUtil redisUtil;
@Value("${payNotifyUrl}")
private String notifyUrl;

/**
 * APP支付
 * 参数加签
 */
@Override
public String aliAppPay(AlipayClient alipayClient, PreOrderParam orderParam) {
 logger.info("AliPayServiceImpl.aliAppPay--->>>\n支付宝预支付开始,\n支付类型为:APP支付,\n订单号为:{}", orderParam.getDh());
 Date date = new Date();
 AlipayTradeAppPayResponse response = null;
 // 发起App支付请求
 AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
 // 订单描述
 model.setBody(orderParam.getBody());
 // 订单标题
 model.setSubject(orderParam.getSubject());
 // 商户订单号 就是商户后台生成的订单号
 model.setOutTradeNo(orderParam.getOutTradeNo());
 // 该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天 (屁股后面的字母一定要带,不然报错)
 model.setTimeoutExpress(DateUtils.toString(date, orderParam.getTimeExpire()));
 // 订单总金额 ,默认单位为元,精确到小数点后两位,取值范围[0.01,100000000]
 model.setTotalAmount(orderParam.getTotalAmount().toString());
 // 销售产品码
 model.setProductCode(PayConstant.ALIPAY_QUICK_WAP_WAY.getKey());
 AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
 request.setBizModel(model);
 // request.setNotifyUrl("商户外网可以访问的异步地址,不写就是不回调");
 request.setNotifyUrl(notifyUrl + PayConstant.ALIPAY_05.getKey() + "/" + orderParam.getAppCode() + "/" + orderParam.getDh());
 //支付成功返回地址
 request.setReturnUrl(orderParam.getRedirectUrl());
 // 通过api的方法请求阿里接口获得反馈
 logger.info("AliPayServiceImpl.aliAppPay----->\n支付宝预支付接口请求信息:{}", JSON.toJSONString(request));
 try {
  response = alipayClient.sdkExecute(request);
 } catch (AlipayApiException e) {
  logger.info("AliPayServiceImpl.aliAppPay----->\n支付宝预下单失败,\n本次下单的订单号为:{},\n相关报错信息为:{}", orderParam.getDh(), response, e);
  throw new BaseException(QYError.msg("调用支付宝预下单接口失败![" + e.getMessage() + "]"));
 }

logger.info("AliPayServiceImpl.aliAppPay----->\n支付宝预支付接口返回信息:{}", JSON.toJSONString(response));
 if (response.isSuccess()) {
  logger.info("AliPayServiceImpl.aliAppPay----->\n支付宝预下单成功,\n本次下单的订单号为:{},商户订单号为:{}", orderParam.getDh(), orderParam.getOutTradeNo());
 } else {
  logger.error("AliPayServiceImpl.aliAppPay----->\n调用支付宝预下单接口失败!\n具体信息为:\n{}", response.getBody());
  throw new BaseException(QYError.msg("调用支付宝预下单接口失败![" + response.getMsg() + "]"));
 }
 return response.getBody();
}

/**
 * 扫码支付
 * 参数加签
 */
@Override
public String aliScanPay(AlipayClient alipayClient, PreOrderParam orderParam) {
 logger.info("AliPayServiceImpl.aliScanPay--->>>\n支付宝预支付开始,\n支付类型为:扫码支付,\n订单号:{}", orderParam.getDh());
 /* AlipayTradePagePayResponse response = null;*/
 AlipayTradePrecreateResponse response = null;
 Date date = new Date();
 /**
  * 设置请求model参数(body、subject、outTradeNo、totalAmount、timeoutExpress;必传)
  */
 AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
 // 订单描述
 model.setBody(orderParam.getBody());
 // 订单标题
 model.setSubject(orderParam.getBody());
 // 商户订单号 就是商户后台生成的订单号
 model.setOutTradeNo(orderParam.getOutTradeNo());
 // 该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天 (屁股后面的字母一定要带,不然报错)
 model.setTimeoutExpress(orderParam.getTimeExpire());
 //model.setSellerId(DateUtils.toString(date, "yyyyMMddHHmmssSSS"));
 // 订单总金额 ,默认单位为元,精确到小数点后两位,取值范围[0.01,100000000]
 model.setTotalAmount(orderParam.getTotalAmount().toString());
 //model.setProductCode(PayConstant.ALIPAY_FAST_INSTANT_TRADE_PAY.getKey());
 // 选填
 /**
  * 创建支付宝扫码支付请求接口类,设置相关请求处理信息,准备请求下单
  */
 AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
 request.setBizModel(model);
 // request.setNotifyUrl("商户外网可以访问的异步地址,不写就是不回调");
 request.setNotifyUrl(notifyUrl + PayConstant.ALIPAY_05.getKey() + "/" + orderParam.getAppCode() + "/" + orderParam.getDh());

//支付成功返回地址
 request.setReturnUrl(orderParam.getRedirectUrl());
 // 通过api的方法请求阿里接口获得反馈 alipayClient.pageExecute(request)
 try {
  logger.info("支付宝扫码付请求报文:{}",JSON.toJSONString(request));
  response = alipayClient.execute(request)/**/;
 } catch (AlipayApiException e) {
  logger.info("AliPayServiceImpl.aliScanPay----->\n支付宝预下单失败,\n本次下单的订单号:{},\n相关报错信息为:{}", orderParam.getDh(), response, e);
  throw new BaseException(QYError.msg("调用支付宝预下单接口失败![" + e.getMessage() + "]"));
 }catch (Exception e){
  e.printStackTrace();
  throw new BaseException(QYError.msg("调用支付宝预下单接口失败![" + e.getMessage() + "]"));
 }

//打印返回信息
 logger.info("AliPayServiceImpl.aliScanPay----->\n支付宝预支付接口返回信息:{}", JSON.toJSONString(response));
 //判断预下单返回状态
 if (response.isSuccess()) {
  logger.info("AliPayServiceImpl.aliScanPay----->\n支付宝预下单成功,\n本次下单的订单号:{},商务订单号为", orderParam.getDh(), orderParam.getOutTradeNo());
 } else {
  logger.error("AliPayServiceImpl.aliScanPay----->\n调用支付宝预下单接口失败!\n具体信息:\n{}", response.getBody());
  throw new BaseException(QYError.msg("调用支付宝预下单接口失败![" + response.getMsg() + "]"));
 }

return response.getQrCode();
}

/**
 * H5支付
 * 参数加签
 */
@Override
public String aliH5Pay(AlipayClient alipayClient, PreOrderParam orderParam) {
 logger.info("AliPayServiceImpl.aliH5Pay--->>>\n支付宝预支付开始,\n支付类型为:H5支付,\n订单号:{}", orderParam.getDh());
 String form = "";
 AlipayTradeWapPayResponse response = null;
 /**
  * 封装请求支付信息
  */
 AlipayTradeWapPayModel payModel = new AlipayTradeWapPayModel();
 payModel.setOutTradeNo(orderParam.getOutTradeNo());
 payModel.setSubject(orderParam.getBody());
 payModel.setTotalAmount(orderParam.getTotalAmount().toString());
 payModel.setBody(orderParam.getBody());
 payModel.setTimeoutExpress(orderParam.getTimeExpire());
 payModel.setProductCode(PayConstant.ALIPAY_QUICK_WAP_WAY.getKey());
 payModel.setQuitUrl(URLEncoder.encode(orderParam.getQuitUrl()));
 /**
  * 创建支付宝H5支付请求接口类,设置相关请求处理信息,准备请求下单
  */
 AlipayTradeWapPayRequest alipay_request = new AlipayTradeWapPayRequest();
 alipay_request.setBizModel(payModel);
 // 设置异步通知地址
 logger.info("通知地址{}", notifyUrl + PayConstant.ALIPAY_05.getKey() + "/" + orderParam.getAppCode() + "/" + orderParam.getDh());
 alipay_request.setNotifyUrl(notifyUrl + PayConstant.ALIPAY_05.getKey() + "/" + orderParam.getAppCode() + "/" + orderParam.getDh());
 // 设置同步地址
 alipay_request.setReturnUrl(URLEncoder.encode(orderParam.getRedirectUrl()));
 // 调用SDK生成表单
 try {
  response = alipayClient.pageExecute(alipay_request);
  if (response.isSuccess()) {
   form = response.getBody();
   logger.info("AliPayServiceImpl.aliH5Pay----->>>>\n支付宝预支付接口返回信息:{}", JSON.toJSONString(response));
  } else {
   logger.info("AliPayServiceImpl.aliH5Pay----->>>>\n支付宝预支付接口返回信息:{}", JSON.toJSONString(response));
   throw new BaseException(QYError.msg("支付宝"));
  }

} catch (AlipayApiException e) {
  logger.info("AliPayServiceImpl.aliH5Pay----->>>>\n支付宝预支付接口返回信息:{}", JSON.toJSONString(response));
  throw new BaseException(QYError.msg("调用支付宝预下单接口失败![" + e.getMessage() + "]"));
 }
 logger.info("AliPayServiceImpl.aliH5Pay----->>>>\n支付宝预支付接口返回信息:{}", JSON.toJSONString(response));
 /**
  * 打印日志,并返回链接
  */
 return form;
}

/**
 * 支付宝通知
 *
 * @param params
 */
@Override
public void aliPayNotify(PayNotify params) {
 logger.info("AliPayServiceImpl.appAliPayNotify-\n阿里服务器消费手机回调参数获取和参数判断-------》》》");
 /**
  * 打印信息
  */
 //校验支付金额
 /*ReturnMsg returnMsg = restTemplate.postForEntity(params.getNoOrderAmountUrl(), params, ReturnMsg.class).getBody();
 if (!returnMsg.isSuccess()) {
  logger.info("WxPayController.wxPayNotify-->\n校验订单金额失败,请核实商务订单号:{}", params);
  throw new BaseException(QYError.msg("校验订单金额失败!商务订单号[" + params.getOutTradeNo() + "]"));
 }*/
 /**
  * 判断支付状态
  */
 if (params.getTradeStatus().equals("TRADE_SUCCESS")) {
  logger.info("AliPayServiceImpl.appAliPayNotify----\n支付宝支付成功!商务订单号[{}]----->>", params.getOutTradeNo(), JSON.toJSONString(params));
 } else {
  logger.error("AliPayServiceImpl.appAliPayNotify---\n支付宝支付失败!商务订单号[{}]---->>", params.getOutTradeNo());
  throw new BaseException(QYError.msg("支付宝支付失败!商务订单号[" + params.getOutTradeNo() + "]"));
 }
}

@Override
public boolean rsaCheckV1(HttpServletRequest request, String appCode) {
 //获取支付宝GET过来反馈信息
 Map<String, String> params = new HashMap<String, String>();
 // 签名验证(对支付宝返回的数据验证,确定是支付宝返回的)
 boolean result = false;
 try {
  // 从支付宝回调的request域中取值
  Map<String, String[]> requestParams = request.getParameterMap();
  for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
   String name = 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] + ",";
   }
   params.put(name, valueStr);
  }
  logger.info("AliPayServiceImpl.appAliPayNotify--\n支付宝通知数据包----->>>>>>>>>>>>>>>{}", JSON.toJSONString(params));
  // 商家编码

AlipayConfig alipayConfig = getConfigByAppCode(appCode);
  result = AlipaySignature.rsaCheckV1(params, alipayConfig.getAliPublicKey(),
    PayConstant.ALIPAY_CHARSET.getKey(), PayConstant.ALIPAY_SIGN_TYPE_RSA2.getKey());
 } catch (Exception e) {
  logger.error("AliPayServiceImpl.appAliPayNotify---\n校验签名失败!商务订单号[{}]---->>", JSON.toJSONString(request), e);
  throw new BaseException(QYError.msg("支付宝支付校验签名失败!"));
 }
 return result;
}

/**
 * 根据商务订单号查询查询支付信息
 *
 * @param alipayClient
 * @param out_trade_no
 * @return
 */
@Override
public AlipayTradeQueryResponse aliPayOrderQuery(AlipayClient alipayClient, String out_trade_no) {
 logger.info("AliPayServiceImpl.aliPayOrderQuery----\n根据商务订单号查询支付宝订单信息,\n商务订单号:[{}]----》》》", out_trade_no);
 AlipayTradeQueryResponse response = null;
 AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
 //设置查询参数
 Map<String, String> bizModel = new HashMap<>();
 bizModel.put("out_trade_no", out_trade_no);
 request.setBizContent(JSON.toJSONString(bizModel));
 //开始查询
 try {
  response = alipayClient.execute(request);
 } catch (AlipayApiException e) {
  logger.error("AliPayServiceImpl.aliPayOrderQuery--->>\n支付宝订单查询失败,\n商务订单号:[{}]", out_trade_no);
  throw new BaseException(QYError.msg("订单号[" + out_trade_no + "],订单支付失败,状态码为[" + response.getTradeStatus() + "]"));
 }

logger.info("AliPayServiceImpl.aliPayOrderQuery---->>\n查询支付宝订单信息,\n商务订单号:[{}],\n返回信息:{}", out_trade_no, JSON.toJSONString(response));
 //查询状态处理
 if (response.isSuccess()) {
  logger.info("AliPayServiceImpl.aliPayOrderQuery--->>\n支付宝订单查询成功,\n商务订单号:[{}]", out_trade_no);
 } else {
  logger.error("AliPayServiceImpl.aliPayOrderQuery--->>\n支付宝订单查询失败,\n商务订单号:[{}]", out_trade_no);
  throw new BaseException(QYError.msg("订单号[" + out_trade_no + "],订单支付失败,状态码为[" + response.getTradeStatus() + "]"));
 }

return response;
}

/**
 * 根据商家编码设置alipay配置信息
 *
 * @param appCode 商家编码
 * @return
 */
@Override
public AlipayClient getAlipayClientByAppCode(String appCode) {
 logger.info("AliPayServiceImpl.getAlipayClientByAppCode--->>\n获取支付宝配置信息:[{}]", appCode);
 AlipayConfig alipayConfig = null;
 /**
  * 获取商家支付宝配置信息(优先级:1-redis,2-mysql,3-用户系统)
  */
 try {
  alipayConfig = getConfigByAppCode(appCode);
  if (alipayConfig == null) {
   logger.info("AliPayServiceImpl.getAlipayClientByAppCode--->>\n获取支付宝支付配置信息失败:[{}]", appCode);
   logger.info("AliPayServiceImpl.getAlipayClientByAppCode--->>\n获取支付宝支付配置信息失败:[{}{}]", appCode,alipayConfig);
   throw new BaseException(QYError.msg("获取支付宝支付配置信息失败!"));
  }
 } catch (Exception e) {
  logger.error("AliPayServiceImpl.getAlipayClientByAppCode--->>\n获取支付宝配置信息失败:[{}]", e);
  throw new BaseException(QYError.msg("获取支付宝配置信息失败!"));
 }
 AlipayClient alipayClient = new DefaultAlipayClient(
   PayConstant.ALIPAY_01.getKey(),
   alipayConfig.getAliAppid(),
   alipayConfig.getAliPrivateKey(),
   PayConstant.ALIPAY_FORMAT.getKey(),
   PayConstant.ALIPAY_CHARSET.getKey(),
   alipayConfig.getAliPublicKey(),
   PayConstant.ALIPAY_SIGN_TYPE_RSA2.getKey());
 return alipayClient;
}

//获取商家支付宝的配置信息
public AlipayConfig getConfigByAppCode(String appCode) {
 AlipayConfig alipayConfig = alipayConfigService.selectByAppCode(appCode);
 return alipayConfig;
}

/**
 * 支付宝退款接口
 * @param aliPayRefundParam
 * @return
 */
public ReturnMsg aliPayRefund(AliPayRefundParam aliPayRefundParam){
 ReturnMsg returnMsg=new ReturnMsg();

String appCode=aliPayRefundParam.getAppCode();
 AlipayClient alipayClient = getAlipayClientByAppCode(appCode);

AlipayTradeRefundResponse response = null;
 AlipayTradeRefundModel model = new AlipayTradeRefundModel();
 //订单支付时传入的商户订单号,不能和 trade_no同时为空。
 model.setOutTradeNo(aliPayRefundParam.getOutTradeNo());
 //支付宝交易号,和商户订单号不能同时为空
 //model.setTradeNo(aliPayRefundParam.getTradeNo());
 //标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传。
 model.setOutRequestNo(aliPayRefundParam.getOutRequestNo());
 //需要退款的金额,该金额不能大于订单金额,单位为元,支持两位小数
 model.setRefundAmount(aliPayRefundParam.getRefundAmount());
 //退款的原因说明
 model.setRefundReason(aliPayRefundParam.getRefundReason());

/**
  * 创建支付宝扫码支付请求接口类,设置相关请求处理信息,准备请求下单
  */
 AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
 request.setBizModel(model);
 //商户外网可以访问的异步地址,不写就是不回调
 request.setNotifyUrl(notifyUrl + PayConstant.ALIPAY_05.getKey() + "/" + aliPayRefundParam.getAppCode() + "/" + aliPayRefundParam.getDh());
 //支付成功返回地址
 request.setReturnUrl(aliPayRefundParam.getRedirectUrl());

// 通过api的方法请求阿里接口获得反馈 alipayClient.pageExecute(request)
 try {
  logger.info("支付宝退款请求完整报文:{}",JSON.toJSONString(request));
  response = alipayClient.execute(request)/**/;
 } catch (AlipayApiException e) {
  logger.info("支付宝退款失败,\n本次下单的订单号:{},\n相关报错信息为:{}", aliPayRefundParam.getDh(), response, e);
  throw new BaseException(QYError.msg("调用支付宝预退款失败![" + e.getMessage() + "]"));
 }catch (Exception e){
  e.printStackTrace();
  throw new BaseException(QYError.msg("支付宝预退款失败![" + e.getMessage() + "]"));
 }

//打印返回信息
 logger.info("支付宝退款失败:{}", JSON.toJSONString(response));
 //判断预下单返回状态
 if (response.isSuccess()&&"Y".equals(response.getFundChange())) {
  logger.info("AliPayServiceImpl.aliScanPay----->\n支付宝退款成功,\n本次下单的订单号:{},商务订单号为,{}", aliPayRefundParam.getDh(), aliPayRefundParam.getOutTradeNo());
  return returnMsg.setData("退款成功");

} else {
  logger.error("AliPayServiceImpl.aliScanPay----->\n调用支付宝退款接口失败!\n具体信息:\n{}", response.getBody());
  throw new BaseException(QYError.msg("调用支付宝退款接口失败![" + response.getBody() + "]"));
 }
}

}

4、WxPayService


package com.qcsoft.payment.service;

import com.qcsoft.commonbean.bean.payment.WxMinConfig;
import com.qcsoft.commonbean.bean.payment.wx.bean.PreOrderParam;
import com.qcsoft.commonbean.bean.payment.wx.bean.WxRefund;
import com.qcsoft.commonbean.bean.payment.wx.bean.entpay.EntPayParam;
import com.qcsoft.commonbean.bean.payment.wx.bean.entpay.EntPayResult;
import com.qcsoft.commonbean.bean.payment.wx.bean.request.WxPayUnifiedOrderRequest;
import com.qcsoft.commonbean.bean.payment.wx.bean.result.BaseWxPayResult;
import com.qcsoft.commonbean.bean.payment.wx.bean.result.WxPayOrderQueryResult;
import com.qcsoft.commonbean.bean.payment.wx.bean.result.WxPayUnifiedOrderResult;
import com.qcsoft.commonbean.bean.payment.wx.config.WxPayConfig;
import com.qcsoft.commonbean.bean.payment.wx.exception.WxPayException;

/**
* 微信预支付
* @param appId 应用ID(微信公众号)
* @param mchId 商务号ID
* @param mchKey 商务号密钥
* @param notifyUrl 异步通知地址
* @param signType 签名类型
* @param body 描述
* @param totalFee 金额
* @param spbillCreateIp app和h5支付需要用户的真实请求地址
* @param tradeType
* @param outTradeNo
* @return
*/
public interface WxPayService {
/**
 *
 * @param config {appId:应用ID,mchId:商务号ID,mchKey:商务号密钥,notifyUrl:异步通知地址,signType:签名类型}
 * @param request {body:订单描述,totalFee:金额,
 *    spbillCreateIp:app和h5支付需要用户的真实请求地址Native支付填调用微信支付API的机器IP,
 *    tradeType:SAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付,统一下单接口trade_type的传参可参考这里,
 *    outTradeNo:商户订单号,productId:商品Id(扫码支付必传,其他选填),openid:公众号openId}
 * @return
 */
WxPayUnifiedOrderResult wxPrePay(WxPayConfig config, WxPayUnifiedOrderRequest request);

/**
 * 根据appCode获取商家微信支付配置
 * @param appCode
 * @return
 */
WxPayConfig getWxPayConfigByAppCode(String appCode,String bmCode);

WxPayConfig getWxMinPayConfigByAppCode(String appCode,String sysSoftwareCode);

/**
 * 封装预下单参数实体
 * @param orderParam 预支付接口参数实体
 * @param order 点单
 * @return
 */
WxPayUnifiedOrderRequest packRequestParam(PreOrderParam orderParam);

/**
 * 查询订单
 * @param appCode 商家编码
 * @param dh 订单号
 * @param sysSoftwareCode
 */
WxPayOrderQueryResult wxPayOrderQuery(String appCode, String bmCode, String dh, Integer type, String sysSoftwareCode);

/**
 * 企业支付
 * @param params
 * @return:
 * @Author:
 * @date:
 */
BaseWxPayResult entPay(EntPayParam params) throws WxPayException;
}

WxPayServiceImpl


package com.qcsoft.payment.service.impl;

import com.alibaba.fastjson.JSON;
import com.qcsoft.commonbean.bean.payment.PayLog;
import com.qcsoft.commonbean.bean.payment.WxConfig;
import com.qcsoft.commonbean.bean.payment.WxMinConfig;
import com.qcsoft.commonbean.bean.payment.common.PayConstant;
import com.qcsoft.commonbean.bean.payment.common.PayNotify;
import com.qcsoft.commonbean.bean.payment.wx.bean.PreOrderParam;
import com.qcsoft.commonbean.bean.payment.wx.bean.entpay.*;
import com.qcsoft.commonbean.bean.payment.wx.bean.request.WxPayOrderQueryRequest;
import com.qcsoft.commonbean.bean.payment.wx.bean.request.WxPayUnifiedOrderRequest;
import com.qcsoft.commonbean.bean.payment.wx.bean.result.BaseWxPayResult;
import com.qcsoft.commonbean.bean.payment.wx.bean.result.WxPayOrderQueryResult;
import com.qcsoft.commonbean.bean.payment.wx.bean.result.WxPayUnifiedOrderResult;
import com.qcsoft.commonbean.bean.payment.wx.config.WxPayConfig;
import com.qcsoft.commonbean.bean.payment.wx.exception.WxPayException;
import com.qcsoft.commonbean.bean.payment.wx.handler.EntPayHandler;
import com.qcsoft.commonbean.bean.payment.wx.handler.WxPayHandler;
import com.qcsoft.commonbean.bean.payment.wx.handler.impl.EntPayHandlerImpl;
import com.qcsoft.commonbean.bean.payment.wx.handler.impl.WxPayHandlerApacheHttpImpl;
import com.qcsoft.payment.commns.exception.BaseException;
import com.qcsoft.payment.commns.exception.QYError;
import com.qcsoft.payment.commns.utils.DateUtils;
import com.qcsoft.payment.commns.utils.RedisUtil;
import com.qcsoft.payment.service.PayLogService;
import com.qcsoft.payment.service.WxConfigService;
import com.qcsoft.payment.service.WxMinConfigService;
import com.qcsoft.payment.service.WxPayService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {
private static final Logger logger = LoggerFactory.getLogger(WxPayServiceImpl.class);

@Value("${payNotifyUrl}")
private String notifyUrl;
@Autowired
private RedisUtil redisUtil;
@Autowired
private WxConfigService wxConfigService;
@Autowired
private WxMinConfigService wxMinConfigService;
@Autowired
private PayLogService payLogService;

/**
 * @param config {appId:应用ID,mchId:商务号ID,mchKey:商务号密钥,notifyUrl:异步通知地址,signType:签名类型}
 * @param request {body:订单描述,totalFee:金额,
 *    spbillCreateIp:app和h5支付需要用户的真实请求地址Native支付填调用微信支付API的机器IP,
 *    tradeType:SAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付,统一下单接口trade_type的传参可参考这里,
 *    outTradeNo:商户订单号,productId:商品Id(扫码支付必传,其他选填),openid:公众号openId} 还有很多参数选填
 * @return
 * @throws WxPayException
 */
@Override
public WxPayUnifiedOrderResult wxPrePay(WxPayConfig config, WxPayUnifiedOrderRequest request) {
 logger.info("WxPayServiceImpl.wxPrePay--->>\n微信预支付,\n商务订单号:[{}]", request.getOutTradeNo());
 WxPayHandler wx = new WxPayHandlerApacheHttpImpl();
 WxPayUnifiedOrderResult orderResult = null;
 wx.setConfig(config);
 log.info("WxPayUnifiedOrderResult ={}", config.getNotifyUrl());
 try {
  orderResult = wx.unifiedOrder(request);
 } catch (WxPayException e) {
  logger.error("WxPayServiceImpl.wxPrePay--->>\n微信预支付失败,\n商务订单号:[{}]", request.getOutTradeNo(), orderResult);
  logger.error("异常信息{}", e.getMessage());
  throw new BaseException(QYError.msg("订单号[" + request.getOutTradeNo() + "]预支付失败!"));
 }
 return orderResult;
}

/**
 * 根据商家编码获取微信商户配置信息
 *
 * @param appCode
 * @return
 */
@Override
public WxPayConfig getWxPayConfigByAppCode(String appCode, String bmCode) {
 logger.info("WxPayServiceImpl.getWxPayConfigByAppCode--->>\n获取微信支付配置信息:appCode[{}],bmCode[{}]", appCode, bmCode);
 WxConfig config = null;
 WxPayConfig wxPayConfig = new WxPayConfig();
 /**
  * 获取商家支付宝配置信息(优先级:1-redis,2-mysql,3-用户系统)
  */
 try {
  //2、mysql
  if (config == null) {
   if (StringUtils.isNotBlank(bmCode)) {
    config = wxConfigService.selectByBmCode(bmCode, appCode);
    //如果部门取不到,则去商家的配置
    if (config == null)
     config = wxConfigService.selectByAppCode(appCode);
   } else {
    config = wxConfigService.selectByAppCode(appCode);
   }
  }
  if (config == null) {
   logger.warn("WxPayServiceImpl.getWxPayConfigByAppCode--->>\n获取微信支付配置信息失败:[{}]", appCode);
   throw new BaseException(QYError.msg("获取微信支付配置信息失败!"));
  }
 } catch (Exception e) {
  logger.error("WxPayServiceImpl.getWxPayConfigByAppCode--->>\n获取微信支付配置信息失败:[{}]", e);
  throw new BaseException(QYError.msg("获取微信支付配置信息失败!"));
 }
 //根据appCode查询商家微信配置信息
 wxPayConfig.setAppId(config.getAppid());
 wxPayConfig.setMchId(config.getMchId());
 wxPayConfig.setMchKey(config.getMchKeySecret());
 wxPayConfig.setSignType(PayConstant.WXPAY_SIGNTYPE_MD5.getKey());
 wxPayConfig.setKeyUrl(config.getCrtPath());
 wxPayConfig.setKeyPath(config.getCrtPath());
 log.info("获取微信公众号配置为 [{}],转为微信支付实体为 [{}]",config,wxPayConfig);
 return wxPayConfig;
}

@Override
public WxPayConfig getWxMinPayConfigByAppCode(String appCode, String sysSoftwareCode) {
 logger.error("WxPayServiceImpl.getWxMinPayConfigByAppCode--->>\n获取微信小程序支付配置信息:[{}]", appCode);
 if (StringUtils.isBlank(sysSoftwareCode)) {
  sysSoftwareCode = "store-service";
 }
 WxMinConfig config = null;
 WxPayConfig wxPayConfig = new WxPayConfig();
 /**
  * 获取商家支付宝配置信息(优先级:1-redis,2-mysql,3-用户系统)
  */
 try {
  if (config == null) {
   //config = wxMinConfigService.selectByAppCode(appCode);
   config = wxMinConfigService.selectBySysSoftwareCode(appCode,sysSoftwareCode);
  }
  if (config == null) {
   logger.warn("WxPayServiceImpl.getWxMinPayConfigByAppCode--->>\n获取微信小程序支付配置信息失败:[{}]", appCode);
   throw new BaseException(QYError.msg("获取微信支付配置信息失败!"));
  }
 } catch (Exception e) {
  logger.error("WxPayServiceImpl.getWxMinPayConfigByAppCode--->>\n获取微信小程序支付配置信息失败:[{}]", e);
  throw new BaseException(QYError.msg("获取微信小程序支付配置信息失败!"));
 }
 //根据appCode查询商家微信配置信息
 wxPayConfig.setAppId(config.getAppid());
 wxPayConfig.setMchId(config.getMchId());
 wxPayConfig.setMchKey(config.getMchKeySecret());
 wxPayConfig.setSignType(PayConstant.WXPAY_SIGNTYPE_MD5.getKey());
 wxPayConfig.setKeyUrl(config.getCrtPath());
 wxPayConfig.setKeyPath(config.getCrtPath());
 log.info("获取微信小程序退款配置为 [{}],转为微信支付实体为 [{}]",config,wxPayConfig);
 return wxPayConfig;
}

/**
 * 封装预下单参数实体
 *
 * @param orderParam 预支付接口参数实体
 * @param order  点单
 * @return
 */
@Override
public WxPayUnifiedOrderRequest packRequestParam(PreOrderParam orderParam) {
 Date date = new Date();
 BigDecimal paramAmount = new BigDecimal(orderParam.getTotalAmount().toString());
 BigDecimal multiplyNum = new BigDecimal("100");
 WxPayUnifiedOrderRequest request = WxPayUnifiedOrderRequest.newBuilder()
   .body(orderParam.getBody())
   .totalFee(paramAmount.multiply(multiplyNum).intValue())
   .spbillCreateIp(orderParam.getReqId())
   .notifyUrl(notifyUrl + PayConstant.WXPAY_09.getKey())
   .tradeType(orderParam.getTradeType())
   .outTradeNo(orderParam.getOutTradeNo())
   .build();
 log.info("WxPayUnifiedOrderRequest = {}", PayConstant.WXPAY_09.getKey());

request.setProductId(orderParam.getDh());
 request.setDetail(orderParam.getSubject());
 PayNotify payNotify = new PayNotify();
 payNotify.setAppCode(orderParam.getAppCode());
 payNotify.setCode(orderParam.getBmCode());
 payNotify.setDh(orderParam.getDh());
 request.setAttach(JSON.toJSONString(payNotify));
 if (orderParam.getTradeType().equals(PayConstant.JSAPI.toString())) {
  request.setOpenid(orderParam.getOpenId());
 }
 //开始时间
 request.setTimeStart(DateUtils.getLastMinute(date, 0));
 //有效期
 request.setTimeExpire(orderParam.getTimeExpire());
 return request;
}

/**
 * 订单查询
 *
 * @param appCode 商家编码
 * @param dh  订单号
 * @param sysSoftwareCode
 * @return
 */
@Override
public WxPayOrderQueryResult wxPayOrderQuery(String appCode, String bmCode, String dh, Integer type, String sysSoftwareCode) {
 logger.info("WxPayServiceImpl.wxPayOrderQuery--->>\n微信订单查询,\n本次查询的商家编码为:[{}],商务订单号:[{}]", appCode, dh);
 WxPayHandler handler = new WxPayHandlerApacheHttpImpl();
 WxPayOrderQueryRequest request = new WxPayOrderQueryRequest();
 WxPayOrderQueryResult queryResult = null;
 WxPayConfig config = null;

try {
  PayLog payLog = payLogService.selectByDh(dh);
  if (payLog==null) {
   //商家的微信支付
   if (type == null || type == 1) {
    bmCode = null;
    config = this.getWxPayConfigByAppCode(appCode, bmCode);
    //部门的微信支付支付
   } else if (type == 2) {
    config = this.getWxPayConfigByAppCode(appCode, bmCode);
    //商家小程序支付
   } else if (type == 3) {
    config = this.getWxMinPayConfigByAppCode(appCode,sysSoftwareCode);
   }
  }else{
   config = JSON.parseObject(payLog.getPayConfigJsonStr(), WxPayConfig.class);
  }
  request.setOutTradeNo(dh);
  handler.setConfig(config);
  queryResult = handler.queryOrder(request);
  logger.info("WxPayServiceImpl.wxPayOrderQuery--->>\n微信订单查询成功,\n返回包信息:[{}]", JSON.toJSONString(queryResult));
 } catch (WxPayException e) {
  logger.error("WxPayServiceImpl.wxPayOrderQuery--->>\n微信订单查询失败,\n商务订单号:[{}]", dh);
  throw new BaseException(QYError.msg("微信订单查询失败,商务订单号:[{}]" + dh + ""));
 }
 return queryResult;
}
/**
 * 企业支付
 * @param params
 * @return: com.qcsoft.commonbean.bean.payment.wx.bean.result.BaseWxPayResult
 * @Author:
 * @date:
 */
@Override
public BaseWxPayResult entPay(EntPayParam params) throws WxPayException {
 WxPayHandler wxPayHandler = new WxPayHandlerApacheHttpImpl();
 WxPayConfig config = null;
 EntPayResult result = null;
 EntPayBankResult bankResult = null;
 if (params.getTradeType() != null && params.getTradeType() == 3) {
  config = this.getWxMinPayConfigByAppCode(params.getAppCode(),params.getSysSoftwareCode());
 } else {
  config = this.getWxPayConfigByAppCode(params.getAppCode(), params.getBmCode());
 }
 config.setUseKey(true);
 wxPayHandler.setConfig(config);
 if (params.getTradeType()==1) {
  EntPayRequest request = packEntPayRequest(params,config);
  EntPayHandler entPayHandler = new EntPayHandlerImpl(wxPayHandler);

result = entPayHandler.entPay(request);
  return result;
 }else{
  EntPayBankRequest request = packEntPayBankRequest(params);
  EntPayHandler entPayHandler = new EntPayHandlerImpl(wxPayHandler);
  bankResult = entPayHandler.payBank(request);
  return bankResult;
 }
}
/**
 * 封装微信企业支付请求参数
 * @param params
 * @return: com.qcsoft.commonbean.bean.payment.wx.bean.entpay.EntPayRequest
 * @Author:
 * @date:
 */
public EntPayRequest packEntPayRequest(EntPayParam params,WxPayConfig config) {
 EntPayRequest request = new EntPayRequest();
 request.setAmount(params.getAmount().multiply(new BigDecimal("10")).intValue());
 request.setCheckName("NO_CHECK");
 request.setOpenid(params.getOpenid());
 request.setSpbillCreateIp(params.getSpbillCreateIp());
 request.setPartnerTradeNo(params.getPartnerTradeNo());
 request.setMchAppid(config.getAppId());
 request.setMchId(config.getMchId());
 request.setDescription(params.getDesc());
 return request;
}

/**
 * 封装银行卡企业支付参数
 * @param params
 * @return: com.qcsoft.commonbean.bean.payment.wx.bean.entpay.EntPayBankRequest
 * @Author:
 * @date:
 */
public EntPayBankRequest packEntPayBankRequest(EntPayParam params) {
 EntPayBankRequest request = new EntPayBankRequest();
 request.setAmount(params.getAmount().multiply(new BigDecimal("10")).intValue());
 request.setBankCode(params.getBankCode());
 request.setEncTrueName(params.getEncTrueName());
 request.setPartnerTradeNo(params.getPartnerTradeNo());
 request.setDescription(params.getDesc());
 return request;
}
}

5、这些类是和数据库交互的增删查该类


@Autowired
private WxConfigService wxConfigService;
@Autowired
private WxMinConfigService wxMinConfigService;
@Autowired
private PayLogService payLogService;
@Autowired
private AlipayConfigService alipayConfigService;
```

来源:https://blog.csdn.net/fangzhihua0927/article/details/110390248

标签:Java,微信支付,支付宝支付
0
投稿

猜你喜欢

  • 详解SpringMVC如何进行数据回显

    2023-09-12 08:48:15
  • Spring Security中的Servlet过滤器体系代码分析

    2023-03-23 19:05:34
  • Java实现马踏棋盘算法

    2023-03-05 04:30:46
  • Android Studio中的Gradle依赖深入讲解

    2022-09-01 11:16:37
  • java模拟hibernate一级缓存示例分享

    2023-06-18 08:43:55
  • C#类的创建与初始化实例解析

    2023-08-05 17:55:31
  • Spring Bean生命周期之BeanDefinition的合并过程详解

    2023-11-29 02:50:35
  • c# 实现雪花分形的示例

    2023-05-10 02:59:56
  • VS2019编写C程序或者CUDA程序出现“无法启动程序,系统找不到指定的文件”问题的详细解决方法

    2022-04-25 08:09:31
  • FragmentStatePagerAdapter保存恢复下拉刷新Fragment内存数据

    2023-07-17 20:36:40
  • Android开发实现的ViewPager引导页功能(动态加载指示器)详解

    2021-10-16 17:40:35
  • 详解C#如何实现隐式类型转换

    2022-08-30 06:32:42
  • IDEA插件EasyCode及MyBatis最优配置步骤详解

    2023-11-09 03:19:19
  • Java抽象类和接口使用梳理

    2022-10-02 08:38:46
  • java跟踪执行的sql语句示例分享

    2022-07-30 20:13:18
  • 关于@RequestLine的使用及配置

    2023-09-23 20:52:19
  • C#操作config文件的具体方法

    2023-09-03 12:18:07
  • springboot 整合 seata的配置过程

    2023-01-13 01:28:33
  • .NET Core使用C#扫描并读取图片中的文字

    2022-03-09 11:06:54
  • 完美解决java读取大文件内存溢出的问题

    2023-07-31 17:53:17
  • asp之家 软件编程 m.aspxhome.com