package cn.stylefeng.rest.ijpay.controller; import cn.hutool.core.net.NetUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import cn.stylefeng.guns.modular.business.dto.request.OrderPayRequest; import cn.stylefeng.guns.modular.business.entity.CounsellingOrder; import cn.stylefeng.guns.modular.business.entity.CourseOrder; import cn.stylefeng.guns.modular.business.entity.OrderConsultOne; import cn.stylefeng.guns.modular.business.entity.OrderMentalTest; import cn.stylefeng.guns.modular.business.service.ICounsellingOrderService; import cn.stylefeng.guns.modular.business.service.ICourseOrderService; import cn.stylefeng.guns.modular.business.service.IOrderConsultOneService; import cn.stylefeng.guns.modular.business.service.IOrderMentalTestService; import cn.stylefeng.rest.ijpay.entity.H5SceneInfo; import cn.stylefeng.rest.ijpay.entity.WxPayBean; import cn.stylefeng.rest.ijpay.entity.request.WxAppPayRequest; import cn.stylefeng.rest.modular.order.service.MentalTestOrderBizService; import cn.stylefeng.roses.kernel.rule.constants.RuleConstants; import cn.stylefeng.roses.kernel.rule.enums.OrderTypeEnum; import cn.stylefeng.roses.kernel.rule.enums.PayTypeEnum; import cn.stylefeng.roses.kernel.rule.pojo.response.ErrorResponseData; import cn.stylefeng.roses.kernel.rule.pojo.response.ResponseData; import cn.stylefeng.roses.kernel.rule.pojo.response.SuccessResponseData; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.google.zxing.BarcodeFormat; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import com.ijpay.core.enums.SignType; import com.ijpay.core.enums.TradeType; import com.ijpay.core.kit.*; import com.ijpay.wxpay.WxPayApi; import com.ijpay.wxpay.WxPayApiConfig; import com.ijpay.wxpay.WxPayApiConfigKit; import com.ijpay.wxpay.model.*; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.util.ResourceUtils; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.*; @Slf4j @Controller @Api(tags = "支付接口") @RequestMapping("/wxPay") public class WxPayController { @Autowired WxPayBean wxPayBean; private String notifyUrl; private String refundNotifyUrl; private static final String USER_PAYING = "USERPAYING"; @Resource IOrderMentalTestService orderMentalTestService; @Resource IOrderConsultOneService orderConsultOneService; @Resource MentalTestOrderBizService mentalTestOrderBizService; @Resource ICourseOrderService courseOrderService; @Resource ICounsellingOrderService counsellingOrderService; /** * 微信APP支付 */ @ApiOperation(value = "微信APP支付") @PostMapping(value = "/appPay") @ResponseBody public ResponseData appPay(@RequestBody @Validated WxAppPayRequest req) { // 支付金额 BigDecimal totalAmount = BigDecimal.valueOf(0); // 订单编号判断订单类型 if (req.getOrderNo().contains(OrderTypeEnum.MENTAL_TEST.getCode())) { // 心理测试订单 OrderMentalTest order = orderMentalTestService.getOrderByNo(req.getOrderNo()); totalAmount = order.getPayAmount(); } else if (req.getOrderNo().contains(OrderTypeEnum.CONSULT_ONE.getCode())) { // 心理咨询1V1订单 OrderConsultOne order = orderConsultOneService.getOrderByNo(req.getOrderNo()); totalAmount = order.getPayAmount(); }else if (req.getOrderNo().startsWith(OrderTypeEnum.COURSE_ORDER.getCode())){ CourseOrder courseOrder = this.courseOrderService.getCourseOrderByNo(req.getOrderNo()); totalAmount = courseOrder.getPayAmount(); } else if (req.getOrderNo().startsWith(OrderTypeEnum.COUNSELLING_ORDER.getCode())) { CounsellingOrder counsellingOrder = this.counsellingOrderService.getCounsellingOrderByNo(req.getOrderNo()); totalAmount = counsellingOrder.getPayAmount(); } // 判断转换后的BigDecimal是否为0 if (totalAmount.compareTo(BigDecimal.ZERO) == 0) { if (req.getOrderNo().startsWith(OrderTypeEnum.MENTAL_TEST.getCode())) { // 心理测试订单 orderMentalTestService.paySuccess(req.getOrderNo(), req.getOrderNo(), String.valueOf(totalAmount), PayTypeEnum.ALIPAY.getCode()); } else if (req.getOrderNo().startsWith(OrderTypeEnum.CONSULT_ONE.getCode())) { // 心理咨询1V1订单 mentalTestOrderBizService.paySuccessOrderConsultOne(req.getOrderNo(), req.getOrderNo(), String.valueOf(totalAmount), PayTypeEnum.ALIPAY.getCode()); } else if (req.getOrderNo().startsWith(OrderTypeEnum.COURSE_ORDER.getCode())) { //课程订单 OrderPayRequest orderPayRequest = new OrderPayRequest(); orderPayRequest.setOrderNo(req.getOrderNo()); orderPayRequest.setTransactionNo(req.getOrderNo()); orderPayRequest.setPayType("2"); orderPayRequest.setOrderType(1); courseOrderService.payCourseOrder(orderPayRequest); } else if (req.getOrderNo().startsWith(OrderTypeEnum.COUNSELLING_ORDER.getCode())) { //咨询订单 OrderPayRequest orderPayRequest = new OrderPayRequest(); orderPayRequest.setOrderNo(req.getOrderNo()); orderPayRequest.setTransactionNo(req.getOrderNo()); orderPayRequest.setPayType("2"); orderPayRequest.setOrderType(2); counsellingOrderService.payCounsellingOrder(orderPayRequest); } return new SuccessResponseData("支付成功"); } // 设置支付配置 WxPayApiConfigKit.putApiConfig(getApiConfig()); //WxPayApiConfigKit.setThreadLocalAppId(wxPayBean.getAppId()); //WxPayApiConfigKit.setThreadLocalWxPayApiConfig(getApiConfig()); // 获取IP String ip = NetUtil.localIpv4s().stream().findFirst().orElse("127.0.0.1"); // 获取微信支付配置 WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig(); // 支付金额X100求整 String totalFee = totalAmount.multiply(BigDecimal.valueOf(100)) .setScale(0, RoundingMode.HALF_UP) .toPlainString(); // 组装支付参数 Map params = UnifiedOrderModel .builder() .appid(wxPayApiConfig.getAppId()) .mch_id(wxPayApiConfig.getMchId()) .nonce_str(WxPayKit.generateStr()) .body(req.getSubject()) .attach(req.getSubject()) .out_trade_no(WxPayKit.generateStr()) // .out_trade_no(req.getOrderNo()) .total_fee(totalFee) .spbill_create_ip(ip) .notify_url(notifyUrl) .trade_type(TradeType.APP.getTradeType()).attach(req.getOrderNo()) .build() .createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5); log.debug("微信APP支付请求params:{}", JSONUtil.toJsonStr(params)); String xmlResult = WxPayApi.pushOrder(false, params); log.debug("微信APP支付结果xml:{}", xmlResult); Map result = WxPayKit.xmlToMap(xmlResult); String returnCode = result.get("return_code"); String resultCode = result.get("result_code"); String returnMsg = result.get("return_msg"); if (!WxPayKit.codeIsOk(returnCode) || !WxPayKit.codeIsOk(resultCode)) { log.error("微信APP支付异常!{}", result); return new ErrorResponseData(returnMsg); } // 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回 String prepayId = result.get("prepay_id"); Map packageParams = WxPayKit.appPrepayIdCreateSign(wxPayApiConfig.getAppId(), wxPayApiConfig.getMchId(), prepayId, wxPayApiConfig.getPartnerKey(), SignType.MD5); log.info("微信APP支付返回参数:{}", JSONUtil.toJsonStr(packageParams)); return new SuccessResponseData(packageParams); } /** * 异步通知 */ @RequestMapping(value = RuleConstants.NOT_LOGIN + "/payNotify", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public String payNotify(HttpServletRequest request) { String xmlMsg = HttpKit.readData(request); log.info("微信支付异步通知:" + xmlMsg); Map params = WxPayKit.xmlToMap(xmlMsg); String returnCode = params.get("return_code"); // 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态 // 注意此处签名方式需与统一下单的签名类型一致 if (WxPayKit.verifyNotify(params, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey(), SignType.MD5)) { if (WxPayKit.codeIsOk(returnCode)) { // 参数文档: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8 String totalFee = new BigDecimal(params.get("total_fee")).divide(BigDecimal.valueOf(100)).toString(); String transactionId = params.get("transaction_id"); // 获取订单号 // String orderNo = params.get("out_trade_no"); String orderNo = params.get("attach"); // 订单编号判断订单类型 if (orderNo.startsWith(OrderTypeEnum.MENTAL_TEST.getCode())) { // 心理测试订单 orderMentalTestService.paySuccess(orderNo, transactionId, totalFee, PayTypeEnum.WXPAY.getCode()); } else if (orderNo.startsWith(OrderTypeEnum.CONSULT_ONE.getCode())) { // 心理咨询1V1订单 mentalTestOrderBizService.paySuccessOrderConsultOne(orderNo, transactionId, totalFee, PayTypeEnum.WXPAY.getCode()); } else if (orderNo.startsWith(OrderTypeEnum.COURSE_ORDER.getCode())) { //课程订单 OrderPayRequest orderPayRequest = new OrderPayRequest(); orderPayRequest.setOrderNo(orderNo); orderPayRequest.setTransactionNo(transactionId); orderPayRequest.setPayType("1"); orderPayRequest.setOrderType(1); courseOrderService.payCourseOrder(orderPayRequest); } else if (orderNo.startsWith(OrderTypeEnum.COUNSELLING_ORDER.getCode())) { //咨询订单 OrderPayRequest orderPayRequest = new OrderPayRequest(); orderPayRequest.setOrderNo(orderNo); orderPayRequest.setTransactionNo(transactionId); orderPayRequest.setPayType("1"); orderPayRequest.setOrderType(2); counsellingOrderService.payCounsellingOrder(orderPayRequest); } // 发送通知等 Map xml = new HashMap(2); xml.put("return_code", "SUCCESS"); xml.put("return_msg", "OK"); return WxPayKit.toXml(xml); } } return null; } /** * 获取Api配置 * @return */ public WxPayApiConfig getApiConfig() { WxPayApiConfig apiConfig; try { apiConfig = WxPayApiConfigKit.getApiConfig(wxPayBean.getAppId()); } catch (Exception e) { apiConfig = WxPayApiConfig.builder() .appId(wxPayBean.getAppId()) .mchId(wxPayBean.getMchId()) .partnerKey(wxPayBean.getPartnerKey()) .certPath(wxPayBean.getCertPath()) .domain(wxPayBean.getDomain()) .build(); } notifyUrl = apiConfig.getDomain().concat("/wxPay" + RuleConstants.NOT_LOGIN + "/payNotify"); refundNotifyUrl = apiConfig.getDomain().concat("/wxPay" + RuleConstants.NOT_LOGIN + "/refundNotify"); return apiConfig; } @GetMapping("/getKey") @ResponseBody public String getKey() { return WxPayApi.getSignKey(wxPayBean.getMchId(), wxPayBean.getPartnerKey(), SignType.MD5); } /** * 微信H5 支付 * 注意:必须再web页面中发起支付且域名已添加到开发配置中 */ @RequestMapping(value = "/wapPay", method = {RequestMethod.POST, RequestMethod.GET}) public void wapPay(HttpServletRequest request, HttpServletResponse response) throws IOException { String ip = IpKit.getRealIp(request); if (StrUtil.isBlank(ip)) { ip = "127.0.0.1"; } H5SceneInfo sceneInfo = new H5SceneInfo(); H5SceneInfo.H5 h5_info = new H5SceneInfo.H5(); h5_info.setType("Wap"); //此域名必须在商户平台--"产品中心"--"开发配置"中添加 h5_info.setWap_url("https://gitee.com/javen205/IJPay"); h5_info.setWap_name("IJPay VIP 充值"); sceneInfo.setH5Info(h5_info); WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig(); Map params = UnifiedOrderModel .builder() .appid(wxPayApiConfig.getAppId()) .mch_id(wxPayApiConfig.getMchId()) .nonce_str(WxPayKit.generateStr()) .body("IJPay 让支付触手可及-H5支付") .attach("Node.js 版:https://gitee.com/javen205/TNWX") .out_trade_no(WxPayKit.generateStr()) .total_fee("1000") .spbill_create_ip(ip) .notify_url(notifyUrl) .trade_type(TradeType.MWEB.getTradeType()) .scene_info(JSON.toJSONString(sceneInfo)) .build() .createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5); String xmlResult = WxPayApi.pushOrder(false, params); log.info(xmlResult); Map result = WxPayKit.xmlToMap(xmlResult); String return_code = result.get("return_code"); String return_msg = result.get("return_msg"); if (!WxPayKit.codeIsOk(return_code)) { throw new RuntimeException(return_msg); } String result_code = result.get("result_code"); if (!WxPayKit.codeIsOk(result_code)) { throw new RuntimeException(return_msg); } // 以下字段在return_code 和result_code都为SUCCESS的时候有返回 String prepayId = result.get("prepay_id"); String webUrl = result.get("mweb_url"); log.info("prepay_id:" + prepayId + " mweb_url:" + webUrl); response.sendRedirect(webUrl); } /** * 公众号支付 */ @RequestMapping(value = "/webPay", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public ResponseData webPay(HttpServletRequest request, @RequestParam("total_fee") String totalFee) { // openId,采用 网页授权获取 access_token API:SnsAccessTokenApi获取 String openId = (String) request.getSession().getAttribute("openId"); if (openId == null) { openId = "11111111"; } if (StrUtil.isEmpty(openId)) { return new ErrorResponseData("openId is null"); } if (StrUtil.isEmpty(totalFee)) { return new ErrorResponseData("请输入数字金额"); } String ip = IpKit.getRealIp(request); if (StrUtil.isEmpty(ip)) { ip = "127.0.0.1"; } WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig(); Map params = UnifiedOrderModel .builder() .appid(wxPayApiConfig.getAppId()) .mch_id(wxPayApiConfig.getMchId()) .nonce_str(WxPayKit.generateStr()) .body("IJPay 让支付触手可及-公众号支付") .attach("Node.js 版:https://gitee.com/javen205/TNWX") .out_trade_no(WxPayKit.generateStr()) .total_fee("1000") .spbill_create_ip(ip) .notify_url(notifyUrl) .trade_type(TradeType.JSAPI.getTradeType()) .openid(openId) .build() .createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5); String xmlResult = WxPayApi.pushOrder(false, params); log.info(xmlResult); Map resultMap = WxPayKit.xmlToMap(xmlResult); String returnCode = resultMap.get("return_code"); String returnMsg = resultMap.get("return_msg"); if (!WxPayKit.codeIsOk(returnCode)) { return new ErrorResponseData(returnMsg); } String resultCode = resultMap.get("result_code"); if (!WxPayKit.codeIsOk(resultCode)) { return new ErrorResponseData(returnMsg); } // 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回 String prepayId = resultMap.get("prepay_id"); Map packageParams = WxPayKit.prepayIdCreateSign(prepayId, wxPayApiConfig.getAppId(), wxPayApiConfig.getPartnerKey(), SignType.MD5); String jsonStr = JSON.toJSONString(packageParams); return new SuccessResponseData(jsonStr); } /** * 扫码模式一 */ @RequestMapping(value = "/scanCode1", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public ResponseData scanCode1(HttpServletRequest request, HttpServletResponse response, @RequestParam("productId") String productId) { try { if (StrUtil.isBlank(productId)) { return new ErrorResponseData("productId is null"); } WxPayApiConfig config = WxPayApiConfigKit.getWxPayApiConfig(); //获取扫码支付(模式一)url String qrCodeUrl = WxPayKit.bizPayUrl(config.getPartnerKey(), config.getAppId(), config.getMchId(), productId); log.info(qrCodeUrl); //生成二维码保存的路径 String name = "payQRCode1.png"; log.info(ResourceUtils.getURL("classpath:").getPath()); boolean encode = QrCodeKit.encode(qrCodeUrl, BarcodeFormat.QR_CODE, 3, ErrorCorrectionLevel.H, "png", 200, 200, ResourceUtils.getURL("classpath:").getPath().concat("static").concat(File.separator).concat(name)); if (encode) { //在页面上显示 return new SuccessResponseData(name); } } catch (Exception e) { e.printStackTrace(); return new ErrorResponseData("系统异常:" + e.getMessage()); } return null; } /** * 扫码支付模式一回调 */ @RequestMapping(value = "/scanCodeNotify", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public String scanCodeNotify(HttpServletRequest request, HttpServletResponse response) { try { String result = HttpKit.readData(request); log.info("scanCodeNotify>>>" + result); /** * 获取返回的信息内容中各个参数的值 */ Map map = WxPayKit.xmlToMap(result); for (String key : map.keySet()) { log.info("key= " + key + " and value= " + map.get(key)); } String appId = map.get("appid"); String openId = map.get("openid"); String mchId = map.get("mch_id"); String isSubscribe = map.get("is_subscribe"); String nonceStr = map.get("nonce_str"); String productId = map.get("product_id"); String sign = map.get("sign"); Map packageParams = new HashMap(6); packageParams.put("appid", appId); packageParams.put("openid", openId); packageParams.put("mch_id", mchId); packageParams.put("is_subscribe", isSubscribe); packageParams.put("nonce_str", nonceStr); packageParams.put("product_id", productId); WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig(); String packageSign = WxPayKit.createSign(packageParams, wxPayApiConfig.getPartnerKey(), SignType.MD5); String ip = IpKit.getRealIp(request); if (StrUtil.isBlank(ip)) { ip = "127.0.0.1"; } Map params = UnifiedOrderModel .builder() .appid(wxPayApiConfig.getAppId()) .mch_id(wxPayApiConfig.getMchId()) .nonce_str(WxPayKit.generateStr()) .body("IJPay 让支付触手可及-扫码支付模式一") .attach("Node.js 版:https://gitee.com/javen205/TNWX") .out_trade_no(WxPayKit.generateStr()) .total_fee("1") .spbill_create_ip(ip) .notify_url(notifyUrl) .trade_type(TradeType.NATIVE.getTradeType()) .openid(openId) .build() .createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5); String xmlResult = WxPayApi.pushOrder(false, params); log.info("统一下单:" + xmlResult); /** * 发送信息给微信服务器 */ Map payResult = WxPayKit.xmlToMap(xmlResult); String returnCode = payResult.get("return_code"); String resultCode = payResult.get("result_code"); if (WxPayKit.codeIsOk(returnCode) && WxPayKit.codeIsOk(resultCode)) { // 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回 String prepayId = payResult.get("prepay_id"); Map prepayParams = new HashMap(10); prepayParams.put("return_code", "SUCCESS"); prepayParams.put("appid", appId); prepayParams.put("mch_id", mchId); prepayParams.put("nonce_str", System.currentTimeMillis() + ""); prepayParams.put("prepay_id", prepayId); String prepaySign; if (sign.equals(packageSign)) { prepayParams.put("result_code", "SUCCESS"); } else { prepayParams.put("result_code", "FAIL"); //result_code为FAIL时,添加该键值对,value值是微信告诉客户的信息 prepayParams.put("err_code_des", "订单失效"); } prepaySign = WxPayKit.createSign(prepayParams, wxPayApiConfig.getPartnerKey(), SignType.MD5); prepayParams.put("sign", prepaySign); String xml = WxPayKit.toXml(prepayParams); log.error(xml); return xml; } } catch (Exception e) { e.printStackTrace(); } return null; } /** * 扫码支付模式二 */ @RequestMapping(value = "/scanCode2", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public ResponseData scanCode2(HttpServletRequest request, HttpServletResponse response, @RequestParam("total_fee") String totalFee) { if (StrUtil.isBlank(totalFee)) { return new ErrorResponseData("支付金额不能为空"); } String ip = IpKit.getRealIp(request); if (StrUtil.isBlank(ip)) { ip = "127.0.0.1"; } WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig(); Map params = UnifiedOrderModel .builder() .appid(wxPayApiConfig.getAppId()) .mch_id(wxPayApiConfig.getMchId()) .nonce_str(WxPayKit.generateStr()) .body("IJPay 让支付触手可及-扫码支付模式二") .attach("Node.js 版:https://gitee.com/javen205/TNWXX") .out_trade_no(WxPayKit.generateStr()) .total_fee("1") .spbill_create_ip(ip) .notify_url(notifyUrl) .trade_type(TradeType.NATIVE.getTradeType()) .build() .createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5); String xmlResult = WxPayApi.pushOrder(false, params); log.info("统一下单:" + xmlResult); Map result = WxPayKit.xmlToMap(xmlResult); String returnCode = result.get("return_code"); String returnMsg = result.get("return_msg"); System.out.println(returnMsg); if (!WxPayKit.codeIsOk(returnCode)) { return new ErrorResponseData("error:" + returnMsg); } String resultCode = result.get("result_code"); if (!WxPayKit.codeIsOk(resultCode)) { return new ErrorResponseData("error:" + returnMsg); } //生成预付订单success String qrCodeUrl = result.get("code_url"); String name = "payQRCode2.png"; boolean encode = QrCodeKit.encode(qrCodeUrl, BarcodeFormat.QR_CODE, 3, ErrorCorrectionLevel.H, "png", 200, 200, request.getSession().getServletContext().getRealPath("/") + File.separator + name); if (encode) { //在页面上显示 return new SuccessResponseData(name); } return null; } /** * 刷卡支付 */ @RequestMapping(value = "/microPay", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public ResponseData microPay(HttpServletRequest request, HttpServletResponse response) { String authCode = request.getParameter("auth_code"); String totalFee = request.getParameter("total_fee"); if (StrUtil.isBlank(totalFee)) { return new ErrorResponseData("支付金额不能为空"); } if (StrUtil.isBlank(authCode)) { return new ErrorResponseData("auth_code参数错误"); } String ip = IpKit.getRealIp(request); if (StrUtil.isBlank(ip)) { ip = "127.0.0.1"; } WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig(); Map params = MicroPayModel.builder() .appid(wxPayApiConfig.getAppId()) .mch_id(wxPayApiConfig.getMchId()) .nonce_str(WxPayKit.generateStr()) .body("IJPay 让支付触手可及-刷卡支付") .attach("Node.js 版:https://gitee.com/javen205/TNWXX") .out_trade_no(WxPayKit.generateStr()) .total_fee("1") .spbill_create_ip(ip) .auth_code(authCode) .build() .createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5); String xmlResult = WxPayApi.microPay(false, params); //同步返回结果 log.info("xmlResult:" + xmlResult); Map result = WxPayKit.xmlToMap(xmlResult); String returnCode = result.get("return_code"); String returnMsg = result.get("return_msg"); if (!WxPayKit.codeIsOk(returnCode)) { //通讯失败 String errCode = result.get("err_code"); if (StrUtil.isNotBlank(errCode)) { //用户支付中,需要输入密码 if (USER_PAYING.equals(errCode)) { //等待5秒后调用【查询订单API】 } } log.info("提交刷卡支付失败>>" + xmlResult); return new ErrorResponseData(returnMsg); } String resultCode = result.get("result_code"); if (!WxPayKit.codeIsOk(resultCode)) { log.info("支付失败>>" + xmlResult); String errCodeDes = result.get("err_code_des"); return new ErrorResponseData(errCodeDes); } //支付成功 return new SuccessResponseData(xmlResult); } /** * 微信小程序支付 */ @RequestMapping(value = "/miniAppPay", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public ResponseData miniAppPay(HttpServletRequest request) { //需要通过授权来获取openId String openId = (String) request.getSession().getAttribute("openId"); String ip = IpKit.getRealIp(request); if (StrUtil.isBlank(ip)) { ip = "127.0.0.1"; } WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig(); Map params = UnifiedOrderModel .builder() .appid(wxPayApiConfig.getAppId()) .mch_id(wxPayApiConfig.getMchId()) .nonce_str(WxPayKit.generateStr()) .body("IJPay 让支付触手可及-小程序支付") .attach("Node.js 版:https://gitee.com/javen205/TNWXX") .out_trade_no(WxPayKit.generateStr()) .total_fee("1000") .spbill_create_ip(ip) .notify_url(notifyUrl) .trade_type(TradeType.JSAPI.getTradeType()) .openid(openId) .build() .createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5); String xmlResult = WxPayApi.pushOrder(false, params); log.info(xmlResult); Map result = WxPayKit.xmlToMap(xmlResult); String returnCode = result.get("return_code"); String returnMsg = result.get("return_msg"); if (!WxPayKit.codeIsOk(returnCode)) { return new ErrorResponseData(returnMsg); } String resultCode = result.get("result_code"); if (!WxPayKit.codeIsOk(resultCode)) { return new ErrorResponseData(returnMsg); } // 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回 String prepayId = result.get("prepay_id"); Map packageParams = WxPayKit.miniAppPrepayIdCreateSign(wxPayApiConfig.getAppId(), prepayId, wxPayApiConfig.getPartnerKey(), SignType.MD5); String jsonStr = JSON.toJSONString(packageParams); log.info("小程序支付的参数:" + jsonStr); return new SuccessResponseData(jsonStr); } @RequestMapping(value = "/queryOrder", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public String queryOrder(@RequestParam(value = "transactionId", required = false) String transactionId, @RequestParam(value = "outTradeNo", required = false) String outTradeNo) { try { WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig(); Map params = OrderQueryModel.builder() .appid(wxPayApiConfig.getAppId()) .mch_id(wxPayApiConfig.getMchId()) .transaction_id(transactionId) .out_trade_no(outTradeNo) .nonce_str(WxPayKit.generateStr()) .build() .createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5); log.info("请求参数:{}", WxPayKit.toXml(params)); String query = WxPayApi.orderQuery(params); log.info("查询结果: {}", query); return query; } catch (Exception e) { e.printStackTrace(); return "系统错误"; } } /** * 企业付款到零钱 */ @RequestMapping(value = "/transfer", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public String transfer(HttpServletRequest request, @RequestParam("openId") String openId) { String ip = IpKit.getRealIp(request); if (StrUtil.isBlank(ip)) { ip = "127.0.0.1"; } WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig(); Map params = TransferModel.builder() .mch_appid(wxPayApiConfig.getAppId()) .mchid(wxPayApiConfig.getMchId()) .nonce_str(WxPayKit.generateStr()) .partner_trade_no(WxPayKit.generateStr()) .openid(openId) .check_name("NO_CHECK") .amount("100") .desc("IJPay 让支付触手可及-企业付款") .spbill_create_ip(ip) .build() .createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5, false); // 提现 String transfers = WxPayApi.transfers(params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId()); log.info("提现结果:" + transfers); Map map = WxPayKit.xmlToMap(transfers); String returnCode = map.get("return_code"); String resultCode = map.get("result_code"); if (WxPayKit.codeIsOk(returnCode) && WxPayKit.codeIsOk(resultCode)) { // 提现成功 } else { // 提现失败 } return transfers; } /** * 查询企业付款到零钱 */ @RequestMapping(value = "/transferInfo", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public String transferInfo(@RequestParam("partner_trade_no") String partnerTradeNo) { try { WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig(); Map params = GetTransferInfoModel.builder() .nonce_str(WxPayKit.generateStr()) .partner_trade_no(partnerTradeNo) .mch_id(wxPayApiConfig.getMchId()) .appid(wxPayApiConfig.getAppId()) .build() .createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5, false); return WxPayApi.getTransferInfo(params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId()); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 获取RSA加密公钥 */ @RequestMapping(value = "/getPublicKey", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public String getPublicKey() { try { WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig(); Map params = new HashMap(4); params.put("mch_id", wxPayApiConfig.getMchId()); params.put("nonce_str", String.valueOf(System.currentTimeMillis())); params.put("sign_type", "MD5"); String createSign = WxPayKit.createSign(params, wxPayApiConfig.getPartnerKey(), SignType.MD5); params.put("sign", createSign); return WxPayApi.getPublicKey(params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId()); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 企业付款到银行卡 */ @RequestMapping(value = "/payBank", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public String payBank() { try { WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig(); //通过WxPayApi.getPublicKey接口获取RSA加密公钥 //假设获取到的RSA加密公钥为PUBLIC_KEY(PKCS#8格式) final String PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6Bl76IwSvBTiibZ+CNRUA6BfahMshZ0WJpHD1GpmvcQjeN6Yrv6c9eIl6gB4nU3isN7bn+LmoVTpH1gHViaV2YyG/zXj4z4h7r+V+ezesMqqorEg38BCNUHNmhnw4/C0I4gBAQ4x0SJOGnfKGZKR9yzvbkJtvEn732JcEZCbdTZmaxkwlenXvM+mStcJaxBCB/h5xJ5VOF5nDbTPzLphIpzddr3zx/Jxjna9QB1v/YSKYXn+iuwruNUXGCvvxBWaBGKrjOdRTRy9adWOgNmtuYDQJ2YOfG8PtPe06ELKjmr2CfaAGrKKUroyaGvy3qxAV0PlT+UQ4ADSXWt/zl0o5wIDAQAB"; Map params = new HashMap(10); params.put("mch_id", wxPayApiConfig.getMchId()); params.put("partner_trade_no", System.currentTimeMillis() + ""); params.put("nonce_str", System.currentTimeMillis() + ""); //收款方银行卡号 params.put("enc_bank_no", RsaKit.encryptByPublicKeyByWx("银行卡号", PUBLIC_KEY)); //收款方用户名 params.put("enc_true_name", RsaKit.encryptByPublicKeyByWx("银行卡持有人姓名", PUBLIC_KEY)); //收款方开户行 params.put("bank_code", "1001"); params.put("amount", "1"); params.put("desc", "IJPay 让支付触手可及-付款到银行卡"); params.put("sign", WxPayKit.createSign(params, wxPayApiConfig.getPartnerKey(), SignType.MD5)); return WxPayApi.payBank(params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId()); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 查询企业付款到银行 */ @RequestMapping(value = "/queryBank", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public String queryBank(@RequestParam("partner_trade_no") String partnerTradeNo) { try { WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig(); Map params = new HashMap(4); params.put("mch_id", wxPayApiConfig.getMchId()); params.put("partner_trade_no", partnerTradeNo); params.put("nonce_str", System.currentTimeMillis() + ""); params.put("sign", WxPayKit.createSign(params, wxPayApiConfig.getPartnerKey(), SignType.MD5)); return WxPayApi.queryBank(params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId()); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 添加分账接收方 */ @RequestMapping(value = "/profitSharingAddReceiver", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public String profitSharingAddReceiver() { try { ReceiverModel receiver = ReceiverModel.builder() .type("PERSONAL_OPENID") .account("openid") .relation_type("PARTNER") .build(); Map params = ProfitSharingModel.builder() .mch_id(wxPayBean.getMchId()) .appid(wxPayBean.getAppId()) .nonce_str(WxPayKit.generateStr()) .receiver(JSON.toJSONString(receiver)) .build() .createSign(wxPayBean.getPartnerKey(), SignType.MD5); log.info("请求参数:{}", WxPayKit.toXml(params)); String result = WxPayApi.profitSharingAddReceiver(params); log.info("请求结果:{}", result); return JSON.toJSONString(WxPayKit.xmlToMap(result)); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 请求单次分账 */ @RequestMapping(value = "/profitSharing", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public String profitSharing(@RequestParam(value = "transactionId") String transactionId) { List list = new ArrayList<>(); list.add(ReceiverModel.builder() .type("PERSONAL_OPENID") .account("openid") .amount(66) .description("IJPay 分账") .build()); Map params = ProfitSharingModel.builder() .mch_id(wxPayBean.getMchId()) .appid(wxPayBean.getAppId()) .nonce_str(WxPayKit.generateStr()) .transaction_id(transactionId) .out_order_no(WxPayKit.generateStr()) .receivers(JSON.toJSONString(list)) .build() .createSign(wxPayBean.getPartnerKey(), SignType.MD5); log.info("请求参数:{}", WxPayKit.toXml(params)); String result = WxPayApi.profitSharing(params, wxPayBean.getCertPath(), wxPayBean.getMchId()); log.info("请求结果:{}", result); return JSON.toJSONString(WxPayKit.xmlToMap(result)); } /** * 微信退款 */ @ApiOperation("微信退款") @RequestMapping(value = RuleConstants.NOT_LOGIN+"/refund", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public String refund(@RequestParam(value = "transactionId", required = false) String transactionId, @RequestParam(value = "outTradeNo", required = false) String outTradeNo) { try { log.info("transactionId: {} outTradeNo:{}", transactionId, outTradeNo); if (StrUtil.isBlank(outTradeNo) && StrUtil.isBlank(transactionId)) { return "transactionId、out_trade_no二选一"; } WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig(); RefundModel refundModel = RefundModel.builder() .appid(wxPayApiConfig.getAppId()) .mch_id(wxPayApiConfig.getMchId()) .nonce_str(WxPayKit.generateStr()) .transaction_id(transactionId) .out_trade_no(outTradeNo) .out_refund_no(WxPayKit.generateStr()) .total_fee("1") .refund_fee("1") .notify_url(refundNotifyUrl) .build(); if (outTradeNo.startsWith(OrderTypeEnum.COURSE_ORDER.getCode())) { //课程订单 CourseOrder courseOrder = this.courseOrderService.getCourseOrderByNo(outTradeNo); //状态:0待支付,1已支付,2已过期,9取消,10退款 if (courseOrder.getStatusFlag().intValue() == 1){ refundModel.setTotal_fee(courseOrder.getPayAmount().toString()); refundModel.setRefund_fee(courseOrder.getPayAmount().toString()); } } else if (outTradeNo.startsWith(OrderTypeEnum.COUNSELLING_ORDER.getCode())) { //咨询订单 CounsellingOrder counsellingOrder = this.counsellingOrderService.getCounsellingOrderByNo(outTradeNo); //状态:0待支付,1已支付,2已完成,9取消,10退款 // if (counsellingOrder.getStatusFlag().intValue() == 1){ refundModel.setTotal_fee(counsellingOrder.getPayAmount().toString()); refundModel.setRefund_fee(counsellingOrder.getPayAmount().toString()); // } } Map params = refundModel.createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5); String refundStr = WxPayApi.orderRefund(false, params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId()); log.info("refundStr: {}", refundStr); return refundStr; } catch (Exception e) { e.printStackTrace(); } return null; } /** * 微信退款查询 */ @RequestMapping(value = "/refundQuery", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public String refundQuery(@RequestParam("transactionId") String transactionId, @RequestParam("out_trade_no") String outTradeNo, @RequestParam("out_refund_no") String outRefundNo, @RequestParam("refund_id") String refundId) { WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig(); Map params = RefundQueryModel.builder() .appid(wxPayApiConfig.getAppId()) .mch_id(wxPayApiConfig.getMchId()) .nonce_str(WxPayKit.generateStr()) .transaction_id(transactionId) .out_trade_no(outTradeNo) .out_refund_no(outRefundNo) .refund_id(refundId) .build() .createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5); return WxPayApi.orderRefundQuery(false, params); } /** * 退款通知 */ @RequestMapping(value = RuleConstants.NOT_LOGIN+"/refundNotify", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public String refundNotify(HttpServletRequest request) { String xmlMsg = HttpKit.readData(request); log.info("退款通知=" + xmlMsg); Map params = WxPayKit.xmlToMap(xmlMsg); String returnCode = params.get("return_code"); // 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态 if (WxPayKit.codeIsOk(returnCode)) { String reqInfo = params.get("req_info"); String decryptData = WxPayKit.decryptData(reqInfo, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey()); log.info("退款通知解密后的数据=" + decryptData); Map requestMap = JSONObject.parseObject(decryptData,HashMap.class); String outTradeNo = requestMap.get("out_trade_no"); // 更新订单信息 if (outTradeNo.startsWith(OrderTypeEnum.COURSE_ORDER.getCode())) { //课程订单 CourseOrder courseOrder = this.courseOrderService.getCourseOrderByNo(outTradeNo); courseOrder.setStatusFlag(9); courseOrder.setRefundTime(new Date()); courseOrder.setRefundAmount(courseOrder.getPayAmount()); this.courseOrderService.update(new LambdaUpdateWrapper() .set(CourseOrder::getStatusFlag,9).set(CourseOrder::getRefundTime,new Date()) .set(CourseOrder::getRefundAmount,courseOrder.getPayAmount()) .eq(CourseOrder::getId,courseOrder.getId())); } else if (outTradeNo.startsWith(OrderTypeEnum.COUNSELLING_ORDER.getCode())) { //咨询订单 CounsellingOrder counsellingOrder = this.counsellingOrderService.getCounsellingOrderByNo(outTradeNo); counsellingOrder.setStatusFlag(9); counsellingOrder.setRefundTime(new Date()); counsellingOrder.setRefundAmount(counsellingOrder.getPayAmount()); this.counsellingOrderService.update(new LambdaUpdateWrapper() .set(CounsellingOrder::getStatusFlag,9).set(CounsellingOrder::getRefundTime,new Date()) .set(CounsellingOrder::getRefundAmount,counsellingOrder.getPayAmount()) .eq(CounsellingOrder::getId,counsellingOrder.getId())); } // 发送通知等 Map xml = new HashMap(2); xml.put("return_code", "SUCCESS"); xml.put("return_msg", "OK"); return WxPayKit.toXml(xml); } return null; } @RequestMapping(value = "/sendRedPack", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public String sendRedPack(HttpServletRequest request, @RequestParam("openId") String openId) { try { String ip = IpKit.getRealIp(request); if (StrUtil.isBlank(ip)) { ip = "127.0.0.1"; } WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig(); Map params = SendRedPackModel.builder() .nonce_str(WxPayKit.generateStr()) .mch_billno(WxPayKit.generateStr()) .mch_id(wxPayApiConfig.getMchId()) .wxappid(wxPayApiConfig.getAppId()) .send_name("IJPay 红包测试") .re_openid(openId) .total_amount("1000") .total_num("1") .wishing("感谢您使用 IJPay") .client_ip(ip) .act_name("感恩回馈活动") .remark("点 start 送红包,快来抢!") .build() .createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5); String result = WxPayApi.sendRedPack(params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId()); System.out.println("发送红包结果:" + result); Map map = WxPayKit.xmlToMap(result); return JSON.toJSONString(map); } catch (Exception e) { e.printStackTrace(); } return null; } }