JAVA 接入微信扫码(Native)支付

本文详细介绍了如何在Web应用中接入微信扫码支付功能,包括配置参数、官方Demo、代码实现、支付流程、回调处理以及异常情况的检查。通过统一下单接口生成预支付交易单,然后返回二维码给前端展示。支付成功后,微信会通过回调地址通知服务器,进行订单状态的验证和更新。整个过程涵盖了从支付到验证的完整流程。
摘要由CSDN通过智能技术生成
一:web网站接入微信扫码支付功能(NATIVE)
二:准备工作

微信支付配置参数
1:appId 商家平台ID
2:mchID 商户平台ID
3:machSecret 商户平台密钥
以上三个参数找老板要(缺一不可)

三:官方DEMO下载地址

https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1
image.png
官方demo在项目的md文件里
image

四:代码
1:maven依赖
<dependency>
    <groupId>com.github.wxpay</groupId>
    <artifactId>wxpay-sdk</artifactId>
    <version>0.0.3</version>
</dependency>

非maven项目下载demo打jar包

2:配置文件

image.png

最后边俩个属性是俩种支付方式的回调地址(也是调用接口必填参数)

3:配置类
@Component
public class WxpayConfig implements WXPayConfig {

    @Autowired
    private WxProperties properties;

    private byte[] certData;

    public WxPayConfig(WxProperties properties) {
		this.properties = properties;
    }

    public WxPayConfig() {
    }
    public WxpayConfig() throws Exception {
        String certPath = "/path/to/apiclient_cert.p12";
        File file = new File(certPath);
        InputStream certStream = new FileInputStream(file);
        this.certData = new byte[(int) file.length()];
        certStream.read(this.certData);
        certStream.close();
    }

    @Override
    public String getAppID() {
        return properties.getAppID();
    }

    @Override
    public String getMchID() {
        return properties.getMchID();
    }

    @Override
    public String getKey() {
        return properties.getKey();
    }

    @Override
    public InputStream getCertStream() {
        ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
        return certBis;
    }

    @Override
    public int getHttpConnectTimeoutMs() {
        return Integer.parseInt(properties.getHttpConnectTimeoutMs());
    }

    @Override
    public int getHttpReadTimeoutMs() {
        return Integer.parseInt(properties.getHttpReadTimeoutMs());
    }
}
4:controller层
    private static final Integer[] PAY_ARR={1,2,3};

    @ApiOperation("学员端提交订单")
    @PostMapping("/student/order/create")
    public DataResult<Map<String,String>> createOrderByStudent(@RequestBody @Valid StuCreateOrderReqVo vo, BindingResult result, HttpServletRequest request){
        log.info("学员端创建订单接收到请求");

        if(result.hasErrors()){
            return new DataResult(BaseResponseCode.DATA_ERROR,result.getFieldError().getDefaultMessage());
        }
        List<Integer> list = Arrays.asList(PAY_ARR);
        if(!list.contains(vo.getPayType()) || vo.getPayType()==null){
            return new DataResult(BaseResponseCode.DATA_ERROR,"支付类型有误");
        }

        //创建订单
        UserOrders userOrders =userOrdersService.stuCreateOrderWeb(vo,request);

        log.info("订单创建成功,走支付流程");
        Map<String,String> map=payOrderService.stuPayOrder(userOrders,request);

        return DataResult.success(map);
    }
5:service层(只写实现类)
/**
     * 拉起支付
     * @param userOrders
     * @return
     */
    public Map<String, String> stuPayOrder(UserOrders userOrders, HttpServletRequest request) {

        Map<String,String> map=null;

        String ipAddr = IPUtils.getIpAddr(request);
        if(userOrders.getPaytype()==1){
            log.info("调用微信统一下单");
            map = wxPayService.unifiedOrder(userOrders, ipAddr);
            if("true".equalsIgnoreCase(map.get("success"))){
                map.put("orderId",userOrders.getId()+"");
            }
        }else if(userOrders.getPaytype()==3){
            log.info("调用支付宝统一下单");
            map = aliPayService.prePay(userOrders, ipAddr);
            if("true".equalsIgnoreCase(map.get("success"))){
                map.put("orderId",userOrders.getId()+"");
            }
        }

        return map;
6:WxService
/**
     * 统一下单:商户先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易后调起支付。
     *
     * @param order    订单信息
     * @param clientIP ip
     */
    public Map<String, String> unifiedOrder(UserOrders order, String clientIP) {

        UserInfo student = sourcePackagesMapper.queryOneStudent(order.getUserinfoId());
        WXPayConfig config = new WxPayConfig(properties);
        WXPay wxpay = new WXPay(config);

        Map<String, String> requestData = new HashMap<>();
        // 商品描述
        requestData.put("body", order.getPackageName());
        // 商户订单号
        requestData.put("out_trade_no", order.getOrderNum());
        long total_fee = (long) (order.getPayPrice() * 100L);
        log.info(" 订单总金额,单位为分:" + total_fee);
        // 订单总金额,单位为分
        requestData.put("total_fee", String.valueOf(total_fee));
        log.info("下单用户IP:" + clientIP);
        // 用户端实际ip
        requestData.put("spbill_create_ip", clientIP);

        Map<String, String> returnData = new HashMap<>();
        Map<String, String> responseData = null;
        // WEB端
        // 接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数
        requestData.put("notify_url", properties.getCallbackUrlWeb());
        
        //我用的是扫码支付所以这儿填NATIVE
        requestData.put("trade_type", "NATIVE");
        requestData.put("product_id", order.getPackageId() + "");
        try {
            responseData = wxpay.unifiedOrder(requestData);
        } catch (Exception e) {
            log.error("请求支付失败", e);
            returnData.put("success", "false");
            returnData.put("msg", "请求支付失败:" + e.getMessage());
        }
        if (null != responseData) {
            if (!"SUCCESS".equals(responseData.get("return_code"))) {
                returnData.put("success", "false");
                returnData.put("msg", "请求支付失败:" + responseData.get("return_msg"));
            } else if (!"SUCCESS".equals(responseData.get("result_code"))) {
                returnData.put("success", "false");
                returnData.put("msg", "请求支付失败:" + responseData.get("err_code") + "-" + responseData.get("err_code_des"));
            } else {
                returnData.put("code_url", responseData.get("code_url"));
                userOrdersMapper.updatePrepayidById(order.getId(), responseData.get("prepay_id"));
                returnData.put("success", "true");
            }
        }
        log.debug("微信支付请求结果:{}", returnData);
        return returnData;
    }
如果接口调用成功 WX会返回code_url(微信付款二维码链接),把它返回给前端生成二维码即可
7:付款后需要接收微信回调(参数:notify_url,回调地址需要外网可以访问,如果你需要测试请用自己的服务器或者内网穿透工具)
回调接口:
    @RequestMapping(value = "/web")
    @ResponseBody
    public String callBackWeb(HttpServletRequest req) throws Exception {
        log.info("接收到微信回调");
        StringBuffer xmlStr = new StringBuffer();
        Scanner s = new Scanner(req.getInputStream(), "UTF-8");
        while(s.hasNextLine()){
            xmlStr.append(s.nextLine());
        }
        s.close();
        log.debug("微信返回的数据XML: {}", xmlStr.toString());

        if(!StringUtils.isEmpty(xmlStr.toString())){
            Map<String, String> map = wxPayService.payCallbackHandle(xmlStr.toString());
            if("true".equalsIgnoreCase(map.get("success"))){

                //接收到微信回调主动去查支付是否成功
                String result = wxPayService.validate(map.get("orderNum"));
                if("OK".equalsIgnoreCase(result)){

                    //我自己的业务逻辑
                    List<UserOrders> orderNum = userOrdersService.queryUserOrderByOrderNum(map.get("orderNum"));
                    if(!orderNum.isEmpty()){
                        if(orderNum.get(0).getStatu()==0){
                            result = userOrdersService.payOrder(map.get("orderNum"));
                            //支付成功修改优惠券使用记录
                            if(orderNum.get(0).getDiscountId()!=0){
                                userOrdersService.updateDiscount(orderNum.get(0).getDiscountId(),map.get("orderNum"));
                            }
                        }
                    }
                    if("OK".equalsIgnoreCase(result)){
                        return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
                    }else{
                        log.error(result);
                    }
                }else{
                    log.error(result);
                }
            }else{
                log.error(map.get("msg"));
            }
        }else{
            log.error("非法请求!");
        }
        return "ERROR";
    }
8:wxPayService代码
/**
     * 校验微信支付回调接口传来的数据
     * @param xmlStr 微信支付回调接口返回的XML数据
     * */
    public Map<String, String> payCallbackHandle(String xmlStr) throws Exception {
        WXPayConfig config = new WxPayConfig(properties);
        WXPay wxpay = new WXPay(config);

        Map<String, String> dataMap = wxpay.processResponseXml(xmlStr);
        log.debug("微信支付回调-微信返回的数据dataMap={}", dataMap);

        Map<String, String> returnData = new HashMap<>();

        if(!"SUCCESS".equals(dataMap.get("return_code"))){
            log.error("微信支付回调错误-{}", dataMap.get("return_msg"));
            returnData.put("success", "false");
            returnData.put("msg", dataMap.get("return_msg"));
        }else if(!"SUCCESS".equals(dataMap.get("result_code"))){
            log.error("微信支付回调错误-{}", dataMap.get("err_code") + "-" + dataMap.get("err_code_des"));
            returnData.put("success", "false");
            returnData.put("msg", dataMap.get("err_code") + "-" + dataMap.get("err_code_des"));
        }else{
            returnData.put("success", "true");
            returnData.put("orderNum", dataMap.get("out_trade_no"));
        }
        return returnData;
    }


/**
     * 校验订单是否已支付
     * @param orderNum 订单号
     * @return 返回"OK"标示已支付,其他表示错误信息
     */
    public String validate(String orderNum) {
        Example example = new Example(UserOrders.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("orderNum",orderNum);
        List<UserOrders> ordersList = userOrdersMapper.selectByExample(example);
        UserOrders order = ordersList.get(0);
        WXPayConfig config = new WxPayConfig(properties);
        WXPay wxpay = new WXPay(config);
        Map<String, String> data = new HashMap<>();
        data.put("out_trade_no", order.getOrderNum());

        try {
            Map<String, String> resp = wxpay.orderQuery(data);
            if(!"SUCCESS".equals(resp.get("return_code"))){
                return resp.get("return_msg");
            }else if(!"SUCCESS".equals(resp.get("result_code"))){
                return resp.get("err_code") + " - " + resp.get("err_code_des");
            }else{
                if("SUCCESS".equals(resp.get("trade_state"))){
                    return "OK";
                }else{
                    return "未支付";
                }
            }
        } catch (Exception e) {
            log.error("检验订单是否已支付出错", e);
            return "校验支付状态出错";
        }
    }
9:工具类 ipUtils
private static Logger logger = LoggerFactory.getLogger(IPUtils.class);

	/**
	 * 获取IP地址
	 * 
	 * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
	 * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
	 */
	public static String getIpAddr(HttpServletRequest request) {
		String ip = null;
		try {
			ip = request.getHeader("x-forwarded-for");
			if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("Proxy-Client-IP");
			}
			if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("WL-Proxy-Client-IP");
			}
			if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("HTTP_CLIENT_IP");
			}
			if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("HTTP_X_FORWARDED_FOR");
			}
			if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getRemoteAddr();
			}
		} catch (Exception e) {
			logger.error("IPUtils ERROR ", e);
		}

		// 使用代理,则获取第一个IP地址
		if (StringUtils.isEmpty(ip) && ip.length() > 15) {
			if (ip.indexOf(",") > 0) {
				ip = ip.substring(0, ip.indexOf(","));
			}
		}

		return ip;
	}

结束 (是不是很简单)

其他微信其他方式支付我也做过一些,老铁们有疑问可以评论或者私信我,咱一起学习共同进步

支付宝支付有时间我会更上

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值