基于springboot的微信公众号JSAPI支付

最近做了一个电商项目,写了微信公众号支付和封装的app支付。用法是大同小异。
在次之前,你需要先了解一下,微信支付的 开发文档。
具体的返回信息,参考开发文档,这里主要是把核心代码和流程写了一下。微信JSAPI支付
转载需注明:https://blog.csdn.net/juan1997/article/details/90647747
百度网盘下载链接
链接:https://pan.baidu.com/s/1Jvm_Tul-Wjd8dI186CPQ_w
提取码:4tpi
一、往pom.xml文件引入包

<!-- 支付sdk -->
			<dependency>
				<groupId>com.egzosn</groupId>
				<artifactId>pay-java-common</artifactId>
				<version>2.12.4</version>
			</dependency>
		<!-- 微信支付 -->
			<dependency>
				<groupId>com.egzosn</groupId>
				<artifactId>pay-java-wx</artifactId>
				<version>2.12.4</version>
			</dependency>

二、在application.yml文件配置微信公众的基础信息。 填写自己的公众号的信息

#  微信公众号支付配置
		weixinpay:
			  mchId:  # 商户Id
			  storePassword:  # 秘钥支付密码
			  appid: 
			  secretKey:  # 秘钥
			  notifyUrl:  #微信支付回调
			  keystore:    # 证书所在位置
			  
		# app微信支付
		appweixinpay:
			  mchId: 
			  appid: 
			  secretKey: 
			  notifyUrl: 
			  keystore: 
			  storePassword: 	

三、创建它所对应的配置信息

/**
		 * 微信公众号的配置信息
		 * @author juan
		 *
		 */
		@Data
		@Component
		@ConfigurationProperties(prefix = "weixinpay")
		public class WeixinAccPayConfig {
			private String mchId;
			private String appid;
			private String secretKey;
			private String notifyUrl;
			private String keystore;
			private String storePassword;
		}		
     
        /**
		 * app微信支付的配置信息
		 * @author juan
		 *
		 */
		@Data
		@Component
		@ConfigurationProperties(prefix = "appweixinpay")
		public class AppWeixinAccPayConfig {
			private String mchId;
			private String appid;
			private String secretKey;
			private String notifyUrl;
			private String keystore;
			private String storePassword;
		}	

四、逻辑代码的实现

/**
		 * 微信公众号的controller类。app的微信支付和公众号的微信支付大同小异。简单地来说就是把WeixinAccPayConfig换成AppWeixinAccPayConfig就可以了。
		 * @author juan
		 *
		 */
		@RestController
		@RequestMapping("/accPay")
		public class WeiXinAccPayController{
			@Autowired
			WeixinAccPayConfig weixinpayConfig;//微信公众号。
			private PayService service = null;
			@PostConstruct
			public void init() {
				WxPayConfigStorage wxPayConfigStorage = new WxPayConfigStorage();
				wxPayConfigStorage.setMchId(weixinpayConfig.getMchId()); // 合作者id(商户号
				wxPayConfigStorage.setAppid(weixinpayConfig.getAppid()); // 应用id
				wxPayConfigStorage.setSecretKey(weixinpayConfig.getSecretKey()); // 密钥
				wxPayConfigStorage.setNotifyUrl(weixinpayConfig.getNotifyUrl()); // 异步回调地址 http://域名:端口号/项目名/回调接口名称
				wxPayConfigStorage.setSignType(SignUtils.MD5.name());
				wxPayConfigStorage.setInputCharset("utf-8");
				// 支付api证书设置,退款必须 方式一
				HttpConfigStorage httpConfigStorage = new HttpConfigStorage();
				httpConfigStorage.setKeystore(weixinpayConfig.getKeystore());// 支付密钥存放位置 文件是以.p12为后缀名字
				httpConfigStorage.setStorePassword(weixinpayConfig.getStorePassword());
				// 是否为证书地址
				httpConfigStorage.setPath(true);
				service = new WxPayService(wxPayConfigStorage, httpConfigStorage);
				// 请求连接池配置
				// 最大连接数
				httpConfigStorage.setMaxTotal(20);
				// 默认的每个路由的最大连接数
				httpConfigStorage.setDefaultMaxPerRoute(10);
				service.setRequestTemplateConfigStorage(httpConfigStorage);
			}
			@ApiOperation("返回订单信息")
			@RequestMapping(value = "weixinpay", method = RequestMethod.POST)
			public Map<String, Object> weixinpay(HttpServletRequest request,在这里可以加前台需要向后台传递的参数) {
			    //备注:这个可以获取预支付的订单,根据需要调用这个接口,可有前台向后台传递参数。然后后台根据需要进行处理。
				init();
				// 在这一步,可以传入一个订单Id,自行去搜索订单信息,并填写以下内容
				PayOrder payOrder = new PayOrder();// 这个就是支付成功后,在微信支付里面返回的信息(支付订单信息)
				// 一下内容需要分情况而定,自行填写。
				payOrder.setSubject("商品名称");
				payOrder.setBody("商品描述");
				payOrder.setAddition("附加信息");
				payOrder.setPrice(new BigDecimal(0.2));// 价格
				payOrder.setOutTradeNo("商户订单号");
				payOrder.setBankType("银行卡类型");
				payOrder.setDeviceInfo("设备信息");
				payOrder.setSpbillCreateIp("支付创建ip");// 可用IPUtils.getIpAddr(request)
				payOrder.setOpenid("用户微信openid");
				payOrder.setTransactionType(WxTransactionType.JSAPI);// 支付方式
				Map orderInfo = service.orderInfo(payOrder);// 返回创建的订单信息
				logger.debug("获取预支付订单信息回参" + orderInfo.toString());
				// 可自行选择 ,是否将支付的流水插入到数据库中。返回的信息由:signType appId timeStamp nonceStr package sign
				return R.ok().put("orderInfo", orderInfo);
			}
			/**
			 * 这就是支付回调地址
			 * 
			 * @param request
			 * @return
			 * @throws IOException
			 */
			@ApiOperation("回调地址")
			@RequestMapping(value = "weixinpayBack")
			public String payBack(HttpServletRequest request) throws IOException {
				init();
				// 获取支付方返回的对应参数
				Map<String, Object> params = service.getParameter2Map(request.getParameterMap(), request.getInputStream());
				if (null == params) {
					logger.debug("通知失败");
					return service.getPayOutMessage("failed", "通知失败").toMessage();
				}
				logger.debug("微信公众号支付结果通知:" + params.toString());
				// 校验
				if (service.verify(params)) {
					// 这里处理业务逻辑 支付成功后的代码逻辑块
					// ......业务逻辑处理块........
					logger.debug("通知支付成功");
					return service.getPayOutMessage("success", "支付成功").toMessage();
				}
				logger.debug("通知支付失败");
				return service.getPayOutMessage("fail", "支付失败").toMessage();
			}
            @ApiOperation("微信公众号退款")
			@RequestMapping(value = "weixinAccRefund")
			public R weixinRefund(这里可以写前台需要向后台传递的参数) {
				init();
				RefundOrder refundOrder = new RefundOrder();//退款订单信息
				refundOrder.setRefundNo("退款单号,每次进行退款的单号,此处唯一");
				refundOrder.setTradeNo("支付平台订单号,交易号");
				refundOrder.setOutTradeNo("商户单号");
				refundOrder.setRefundAmount(new BigDecimal(0.2));//退款金额
				refundOrder.setTotalAmount(new BigDecimal(0.5));//订单总金额
				refundOrder.setOrderDate(new Date());//退款交易日期
				refundOrder.setDescription("退款说明");
				Map<String, Object> refund = service.refund(refundOrder);//微信退款
				//退款成功后,写其他的逻辑
				logger.debug("微信公众号退款结果:=" + refund.toString());
				
				return R.ok();

			} 
		}		
要生成微信支付二维码,可以使用微信支付官方提供的接口,以下是基于 Spring Boot 的简单实现步骤: 1. 引入相关依赖 ```xml <dependency> <groupId>com.github.wxpay</groupId> <artifactId>wxpay-sdk</artifactId> <version>3.0.9</version> </dependency> <dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.3.3</version> </dependency> <dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId> <version>3.3.3</version> </dependency> ``` 2. 配置微信支付相关参数 ```java @Configuration public class WxPayConfig { // 微信支付分配的商户号 @Value("${wxpay.mchId}") private String mchId; // 微信支付分配的终端设备号 @Value("${wxpay.deviceInfo}") private String deviceInfo; // 微信支付分配的公众账号ID @Value("${wxpay.appId}") private String appId; // 微信支付分配的商户密钥 @Value("${wxpay.key}") private String key; // 微信支付异步通知地址 @Value("${wxpay.notifyUrl}") private String notifyUrl; // 微信支付统一下单接口地址 @Value("${wxpay.unifiedOrderUrl}") private String unifiedOrderUrl; // 微信支付查询订单接口地址 @Value("${wxpay.orderQueryUrl}") private String orderQueryUrl; // 微信支付关闭订单接口地址 @Value("${wxpay.closeOrderUrl}") private String closeOrderUrl; // 微信支付申请退款接口地址 @Value("${wxpay.refundUrl}") private String refundUrl; // 微信支付查询退款接口地址 @Value("${wxpay.refundQueryUrl}") private String refundQueryUrl; // 微信支付下载对账单接口地址 @Value("${wxpay.downloadBillUrl}") private String downloadBillUrl; // 微信支付交易保障接口地址 @Value("${wxpay.reportUrl}") private String reportUrl; // 签名类型 private final String SIGN_TYPE = "MD5"; // 连接超时时间 private final int CONNECT_TIMEOUT = 5000; // 读取超时时间 private final int READ_TIMEOUT = 10000; // 微信支付API证书路径 @Value("${wxpay.certPath}") private String certPath; // 微信支付API证书密码 @Value("${wxpay.certPassword}") private String certPassword; /** * 初始化微信支付配置 */ @Bean public WXPay wxPay() throws Exception { WXPayConfigImpl config = new WXPayConfigImpl(); config.setAppID(appId); config.setMchID(mchId); config.setKey(key); config.setDeviceInfo(deviceInfo); config.setSignType(SIGN_TYPE); config.setUnifiedOrderUrl(unifiedOrderUrl); config.setOrderQueryUrl(orderQueryUrl); config.setCloseOrderUrl(closeOrderUrl); config.setRefundUrl(refundUrl); config.setRefundQueryUrl(refundQueryUrl); config.setDownloadBillUrl(downloadBillUrl); config.setReportUrl(reportUrl); return new WXPay(config, notifyUrl, true, true); } /** * 微信支付配置类 */ class WXPayConfigImpl extends WXPayConfig { private String appId; private String mchId; private String key; private String deviceInfo; private String signType; private String unifiedOrderUrl; private String orderQueryUrl; private String closeOrderUrl; private String refundUrl; private String refundQueryUrl; private String downloadBillUrl; private String reportUrl; public void setAppID(String appId) { this.appId = appId; } public void setMchID(String mchId) { this.mchId = mchId; } public void setKey(String key) { this.key = key; } public void setDeviceInfo(String deviceInfo) { this.deviceInfo = deviceInfo; } public void setSignType(String signType) { this.signType = signType; } public void setUnifiedOrderUrl(String unifiedOrderUrl) { this.unifiedOrderUrl = unifiedOrderUrl; } public void setOrderQueryUrl(String orderQueryUrl) { this.orderQueryUrl = orderQueryUrl; } public void setCloseOrderUrl(String closeOrderUrl) { this.closeOrderUrl = closeOrderUrl; } public void setRefundUrl(String refundUrl) { this.refundUrl = refundUrl; } public void setRefundQueryUrl(String refundQueryUrl) { this.refundQueryUrl = refundQueryUrl; } public void setDownloadBillUrl(String downloadBillUrl) { this.downloadBillUrl = downloadBillUrl; } public void setReportUrl(String reportUrl) { this.reportUrl = reportUrl; } @Override public String getAppID() { return appId; } @Override public String getMchID() { return mchId; } @Override public String getKey() { return key; } @Override public InputStream getCertStream() { try { return new FileInputStream(new File(certPath)); } catch (FileNotFoundException e) { e.printStackTrace(); } return null; } @Override public int getHttpConnectTimeoutMs() { return CONNECT_TIMEOUT; } @Override public int getHttpReadTimeoutMs() { return READ_TIMEOUT; } @Override public String getDeviceInfo() { return deviceInfo; } @Override public String getSignType() { return signType; } @Override public String getUnifiedOrderUrl() { return unifiedOrderUrl; } @Override public String getOrderQueryUrl() { return orderQueryUrl; } @Override public String getCloseOrderUrl() { return closeOrderUrl; } @Override public String getRefundUrl() { return refundUrl; } @Override public String getRefundQueryUrl() { return refundQueryUrl; } @Override public String getDownloadBillUrl() { return downloadBillUrl; } @Override public String getReportUrl() { return reportUrl; } } } ``` 3. 调用微信支付统一下单接口,获取支付二维码 ```java @RestController @RequestMapping("/wxpay") public class WxPayController { @Autowired private WXPay wxPay; /** * 生成微信支付二维码 * * @param orderId 订单ID * @param amount 支付金额 * @return 二维码图片Base64编码字符串 */ @GetMapping("/qrcode") public String generateQrCode(@RequestParam("order_id") String orderId, @RequestParam("amount") int amount) { try { Map<String, String> data = new HashMap<>(); data.put("body", "xxxx"); // 商品描述 data.put("out_trade_no", orderId); // 订单号 data.put("total_fee", String.valueOf(amount)); // 支付金额,单位为分 data.put("spbill_create_ip", "127.0.0.1"); // 发起支付的客户端IP data.put("notify_url", "http://localhost/wxpay/notify"); // 支付成功的回调地址 data.put("trade_type", "NATIVE"); // 交易类型,JSAPI:公众号支付;NATIVE:扫码支付;APP:APP支付 data.put("product_id", orderId); // 商品ID,trade_type=NATIVE时必填 // 调用微信支付统一下单接口 Map<String, String> result = wxPay.unifiedOrder(data); String return_code = result.get("return_code"); String result_code = result.get("result_code"); if ("SUCCESS".equals(return_code) && "SUCCESS".equals(result_code)) { String codeUrl = result.get("code_url"); // 生成二维码 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); BitMatrix bitMatrix = new MultiFormatWriter().encode(codeUrl, BarcodeFormat.QR_CODE, 300, 300); MatrixToImageWriter.writeToStream(bitMatrix, "png", outputStream); byte[] bytes = outputStream.toByteArray(); return Base64.getEncoder().encodeToString(bytes); } else { String err_code_des = result.get("err_code_des"); throw new RuntimeException(err_code_des); } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e.getMessage()); } } } ``` 以上就是基于 Spring Boot 的微信支付二维码生成的简单实现了。需要注意的是,微信支付二维码的有效期为2小时,超过时间后需要重新生成。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值