微信APP支付之IJpay的使用

写在开始:一个搬砖程序员的随缘记录

微信支付相对其他支付,比如支付宝支付坑比较多。一直报签名失败。签名参数顺序、数据类型,加密类型这些都需要注意,用第三方的比较省心。

IJpay介绍:

聚合支付,IJPay 让支付触手可及,封装了微信支付、QQ支付、支付宝支付、京东支付、银联支付、PayPal支付等常用的支付方式以及各种常用的接口。不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。

项目整体目录:

一、获取微信APP支付必须的参数

1、appId:微信开放平台上面的应用appid
在这里插入图片描述

2、mchId:微信商户号,注意这是登陆的商户平台,不是开放平台了
在这里插入图片描述
3、mchKey:API密钥
登录微信商户平台—>账户中心—>API安全—>设置秘钥
在这里插入图片描述
4、然后在微信开放平台上面的应用支付功能必须是开通的,还要绑定商户平台对应的商户号才可以
在这里插入图片描述
在这里插入图片描述
获取到上面所需要的必须参数下面就开始进行项目配置

二、项目配置

1、需要引入的的jar包

		<!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        
        <!-- swagger-ui -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.5.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.5.0</version>
        </dependency>
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>swagger-bootstrap-ui</artifactId>
            <version>1.8.1</version>
        </dependency>

        <!-- IJPay -->
        <dependency>
            <groupId>com.github.javen205</groupId>
            <artifactId>IJPay-All</artifactId>
            <version>2.2.0</version>
        </dependency>

        <!--fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.7</version>
        </dependency>

2、application.yml

wxpay:
  appId: # appid
  mchId: # 商户号
  mchKey: # 秘钥
  notifyUrl: http://127.0.0.1:8080/wxPay/wxPayNotice #微信支付回调地址

3、微信配置类

微信配置参数类
WxPayProperties.Java

package com.cn.wxpay.config;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;

/**
 * @Author: demo
 * @Date: 2020/9/23 15:51
 */
@Data
public class WxPayProperties {
    /**
     * appid.
     */
    @Value("${wxpay.appId}")
    private String appId;

    /**
     * 微信支付商户号.
     */
    @Value("${wxpay.mchId}")
    private String mchId;

    /**
     * 微信支付商户密钥.
     */
    @Value("${wxpay.mchKey}")
    private String mchKey;

    /**
     * 异步回调地址
     */
    @Value("${wxpay.notifyUrl}")
    private String notifyUrl;
}

创建WxPayProperties的实例
WxConfig.Java

package com.cn.wxpay.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author: demo
 * @Date: 2020/9/23 15:51
 */
@Configuration
public class WxConfig {
    @Bean("WxPayProperties")
    public WxPayProperties wxPayProperties(){
        return new WxPayProperties();
    }
}

4、Swagger配置文件

SwaggerConfig.Java

package com.cn.wxpay.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * @Author: demo
 * @Date: 2020/9/23 15:51
 */
@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Bean
    public Docket customDocket() {
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("swagger RESTful APIs")
                .description("swagger RESTful APIs")
                .termsOfServiceUrl("http://www.test.com/")
                .contact("xiaoymin@foxmail.com")
                .version("1.0")
                .build();
    }
}

5、微信支付业务实现相关

订单实体类
TblAutoOrderDat.Java

package com.cn.wxpay.entity;

import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;

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

/**
 * @Author: demo
 * @Date: 2020/9/23 15:51
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(value = "订单实体类")
public class TblAutoOrderDat {
    @ApiModelProperty(value = "id")
    private Integer id;

    @ApiModelProperty(value = "商品描述")
    private String attach;

    @ApiModelProperty(value = "交易类型")
    private String tradeType;

    @ApiModelProperty(value = "订单号")
    private String orderId;

    @ApiModelProperty(value = "订单金额")
    private BigDecimal totalFee;

    @ApiModelProperty(value = "微信支付订单号")
    private String transactionId;

    @ApiModelProperty(value = "支付时间")
    private Date payTime;

    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    @ApiModelProperty(value = "创建时间")
    private Date createTime;

    @ApiModelProperty(value = "创建人")
    private Integer createUser;

    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    @ApiModelProperty(value = "修改时间")
    private Date updateTime;

    @ApiModelProperty(value = "创建人")
    private Integer updateUser;

    @ApiModelProperty(value = "是否删除 1:已删除 0:未删除")
    private Boolean isDelete;
}

微信工具类
WxPayUtil.Java

package com.cn.wxpay.util;

import java.util.Map;

/**
 * @Author: demo
 * @Date: 2020/9/23 15:51
 */
public class WxPayUtil {
    /**
     * 将map转换为xml
     */
    public static String getMapToXml(Map<String, String> param) {
        StringBuilder sb = new StringBuilder();
        sb.append("<xml>");
        for (Map.Entry<String, String> entry : param.entrySet()) {
            sb.append("<" + entry.getKey() + ">");
            sb.append(entry.getValue());
            sb.append("</" + entry.getKey() + ">");
        }
        sb.append("</xml>");
        return sb.toString();
    }
}

IP转换类
IpKit.Java

package com.cn.wxpay.config;

import javax.servlet.http.HttpServletRequest;

/**
 * @author demo
 * @Date: 2020/9/23 15:51
 */
public class IpKit {
    private final static String UNKNOWN = "unknown";

    public static String getRealIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    public static String getRealIpV2(HttpServletRequest request) {
        String accessIp = request.getHeader("x-forwarded-for");
        if (null == accessIp) {
			return request.getRemoteAddr();
		}
        return accessIp;
    }
}

业务类
WxPayController.Java

package com.cn.wxpay.controller;

import com.alibaba.fastjson.JSON;
import com.cn.wxpay.config.IpKit;
import com.cn.wxpay.config.WxPayProperties;
import com.cn.wxpay.entity.TblAutoOrderDat;
import com.cn.wxpay.util.WxPayUtil;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.enums.TradeType;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.model.UnifiedOrderModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: demo
 * @Date: 2020/9/23 15:51
 */
@RestController
@Slf4j
@RequestMapping("/wxPay")
public class WxPayController {
    @Autowired
    private WxPayProperties wxPayProperties;

    /**
     * 微信APP支付
     *
     * @param attach   订单描述:比如会员卡充值、商品名称
     * @param totalFee 支付金额
     * @return 微信支付返回
     */
    @GetMapping(value = "/appPay")
    @ResponseBody
    public Map<String, String> appPay(HttpServletRequest request, @RequestParam("totalFee") BigDecimal totalFee, @RequestParam("attach") String attach) {
        String ip = IpKit.getRealIp(request);
        if (StringUtils.isEmpty(ip)) {
            ip = "127.0.0.1";
        }
        Map<String, String> params = UnifiedOrderModel
                .builder()
                .appid(wxPayProperties.getAppId())
                .mch_id(wxPayProperties.getMchId())
                .nonce_str(WxPayKit.generateStr())
                .body(attach)
                .attach(attach)
                .out_trade_no(WxPayKit.generateStr())
                .total_fee(String.valueOf(totalFee.multiply(new BigDecimal(100)).intValue()))
                .spbill_create_ip(ip)
                .notify_url(wxPayProperties.getNotifyUrl())
                .trade_type(TradeType.APP.getTradeType())
                .build()
                .createSign(wxPayProperties.getMchKey(), SignType.MD5);

        String xmlResult = WxPayApi.pushOrder(false, params);

        log.info(xmlResult);
        Map<String, String> result = WxPayKit.xmlToMap(xmlResult);

        String returnCode = result.get("return_code");
        String returnMsg = result.get("return_msg");
        if (!WxPayKit.codeIsOk(returnCode)) {
            log.info("错误信息:"+returnMsg);
        }
        String resultCode = result.get("result_code");
        if (!WxPayKit.codeIsOk(resultCode)) {
            log.info("错误信息:"+returnMsg);
        }
        // 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回
        String prepayId = result.get("prepay_id");

        Map<String, String> packageParams = WxPayKit.appPrepayIdCreateSign(wxPayProperties.getAppId(), wxPayProperties.getMchId(), prepayId,
                wxPayProperties.getMchKey(), SignType.MD5);

        String jsonStr = JSON.toJSONString(packageParams);
        log.info("返回apk的参数:" + jsonStr);
        return packageParams;
    }

    /**
     * 微信回调接口
     */
    @PostMapping("/wxPayNotice")
    public String parseOrderNotifyResult(@RequestBody String xmlData) throws ParseException {
        Map<String, String> map = new HashMap<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        log.info("微信回调开始了");
        //这里我只进行了部分回调信息的保存,更多参数请查看微信支付官方api:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8
        Map<String, String> resultMap = WxPayKit.xmlToMap(xmlData);
        log.info("resultMap:" + resultMap);
        /*----------------------分割线,下面的是业务代码,根据自己业务进行修改--------------------------*/
        //订单成功业务处理
        if ("SUCCESS".equals(resultMap.get("result_code"))) {
            // 根据resultMap处理订单业务
            TblAutoOrderDat tblAutoOrderDat = new TblAutoOrderDat();
            //订单描述,比如:会员卡充值,商品信息
            tblAutoOrderDat.setAttach(resultMap.get("attach"));
            //交易类型 比如:JSAPI、NATIVE、APP
            tblAutoOrderDat.setTradeType(resultMap.get("trade_type"));
            //商户订单号 商家生成,传给微信返回的
            tblAutoOrderDat.setOrderId(resultMap.get("out_trade_no"));
            //订单金额 订单总金额,单位为分,我这里转换成元了
            tblAutoOrderDat.setTotalFee(new BigDecimal(resultMap.get("total_fee")).divide(new BigDecimal(100)));
            //微信支付订单号
            tblAutoOrderDat.setTransactionId(resultMap.get("transaction_id"));
            //支付完成时间
            String newDate = resultMap.get("time_end");
            tblAutoOrderDat.setPayTime(sdf.parse(newDate.substring(0, 4) + "-" + newDate.substring(4, 6) + "-" + newDate.substring(6, 8) + " " + newDate.substring(8, 10) + ":" + newDate.substring(10, 12) + ":" + newDate.substring(12, 14)));
            //业务实现,把订单信息保存到数据库
            //tblAutoOrderDatService.add(tblAutoOrderDat);
        }
        /*----------------------分割线,业务结束--------------------------*/

        map.put("return_code", "SUCCESS");
        map.put("return_msg", "OK");
        return WxPayUtil.getMapToXml(map);
    }
	
	/**
     * 根据微信订单号查询订单状态
     *
     * @param transactionId 微信订单号
     * @return SUCCESS/FAIL
     */
    @GetMapping("/getOrderStates/{transactionId}")
    public String getOrderStates(@PathVariable("transactionId") String transactionId) {
        Map<String, String> params = OrderQueryModel
                .builder()
                .appid(wxPayProperties.getAppId())
                .mch_id(wxPayProperties.getMchId())
                .transaction_id(transactionId)
                .nonce_str(WxPayKit.generateStr())
                .build()
                .createSign(wxPayProperties.getMchKey(), SignType.MD5);
        String xml = WxPayApi.orderQuery(false, params);
        Map<String, String> resultMap = WxPayKit.xmlToMap(xml);
        log.info("resultMap:" + resultMap);
        return resultMap.get("result_code");
    }
}

还有一个在和APP前端对接的问题很坑。官方API的问题.导致后端的签名已经通过.APP拉不起支付。报支付签名验证失败。遇到此类的问题可参考下。
在这里插入图片描述
Over.

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值