Java 微信jsapi支付

news/2025/2/7 14:37:26/

spring boot微信jsapi支付

  • 话不多说,撸起袖子就是干,下面上源码
    • pom.xml
    • 配置文件 resources/wx.properties
    • 配置类
    • service(WechatPayService)
    • 上impl(WechatPayServiceImpl)之前还是先上一个获取IP的工具类和返回工具类( ResResult)
      • ResResult
      • GetRealyIp
    • impl(WechatPayServiceImpl)
    • controller(WeichatPayController )
    • 前端(我这里是没有前后端分离,引擎使用的是thymeleaf)
      • 终于到最后一步了html,新建一个pay.html
    • spring boot微信支付到此结束!

话不多说,撸起袖子就是干,下面上源码

pom.xml

<dependency><groupId>com.github.wxpay</groupId><artifactId>wxpay-sdk</artifactId><version>0.0.3</version>
</dependency>

配置文件 resources/wx.properties

#未知是否再支付的时候必传
pay.appSecret=你自己的appSecret
pay.appID=你自己的appID
#必传
pay.mchID=你自己的mchID
#必传,但不参与签名
pay.key=自己的key
#随机数 必传
pay.nonceStr=
#必传,支付成功后的通知地址,通知url必须为外网可访问的url,不能携带参数。
pay.notifyUrl=http://***********/pay/hasOrder
#必传,终端IP支持IPV4和IPV6两种格式的IP地址。用户的客户端IP,这里测试就写死 
pay.spbillCreateIp= 127.0.0.1
#支付方式
pay.tradeType=JSAPI
#设备信息,非必须
pay.deviceInfo=WEB
#JSAPI方式必传,只是这里用测试测试就写死
pay.openid=oPgg30mSXJTvd372-pgnyb1M9aEI
#HTTP(S) 连接超时时间,单位毫秒
pay.httpConnectTimeoutMs=180000
#HTTP(S) 读数据超时时间,单位毫秒
pay.httpReadTimeoutMs=180000
#证书路径 非必传
pay.certPath=E:/******

配置类

import com.github.wxpay.sdk.WXPayConfig;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;@Data
@Component
@PropertySource(value = "classpath:wx.properties")
@ConfigurationProperties(prefix = "pay")
public class Pay  implements WXPayConfig{private String appSecret;// 公众账号IDprivate String appID;// 商户号private String mchID;// 设备号private String deviceInfo;// 商户的key【API密匙】private String key;// api请求地址//private String url;// 服务器异步通知页面路径private String notifyUrl;private String spbillCreateIp;private String tradeType;private String openid;/*** HTTP(S) 连接超时时间,单位毫秒*/private int httpConnectTimeoutMs;/*** HTTP(S) 读数据超时时间,单位毫秒*/private int httpReadTimeoutMs;/*** API证书绝对路径*/private String certPath;private String weChatRedirectUrl;@Overridepublic InputStream getCertStream() {File certFile = new File(certPath);InputStream inputStream = null;try {inputStream = new FileInputStream(certFile);} catch (FileNotFoundException e) {e.printStackTrace();}return inputStream;}@Overridepublic String getKey() {
//        if (useSandbox) {
//            return sandboxKey;
//        }return key;}}

service(WechatPayService)

public interface WechatPayService {ResResult goWeChatPay(String money,String des, HttpServletRequest request) throws Exception;String reply(HttpServletRequest request, HttpServletResponse response) throws IOException;
}

上impl(WechatPayServiceImpl)之前还是先上一个获取IP的工具类和返回工具类( ResResult)

ResResult

@Data
public  class ResResult {private int code=200;private Object data;private String description="请求成功!";public  ResResult() {}public  ResResult ok(){return this;}public ResResult data(Object data){this.data=data;return this;}public ResResult err(int code,Object data,String des){this.code=code;this.data=data;this.description=des;return this;}public ResResult err(int code,Object data){this.code=code;this.data=data;this.description="请求失败!";return this;}public ResResult err(Object data,String des){this.code=500;this.data=data;this.description=des;return this;}static class Nei{private static ResResult resResult=new ResResult();}
}

GetRealyIp


import javax.servlet.http.HttpServletRequest;public class GetRealyIp {public static String getIPAddress(HttpServletRequest request) {String ip = null;//X-Forwarded-For:Squid 服务代理String ipAddresses = request.getHeader("X-Forwarded-For");if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {//Proxy-Client-IP:apache 服务代理ipAddresses = request.getHeader("Proxy-Client-IP");}if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {//WL-Proxy-Client-IP:weblogic 服务代理ipAddresses = request.getHeader("WL-Proxy-Client-IP");}if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {//HTTP_CLIENT_IP:有些代理服务器ipAddresses = request.getHeader("HTTP_CLIENT_IP");}if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {//X-Real-IP:nginx服务代理ipAddresses = request.getHeader("X-Real-IP");}//有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IPif (ipAddresses != null && ipAddresses.length() != 0) {ip = ipAddresses.split(",")[0];}//还是不能获取到,最后再通过request.getRemoteAddr();获取if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {ip = request.getRemoteAddr();}return ip;}
}

impl(WechatPayServiceImpl)


@Service
public class WechatPayServiceImpl implements WechatPayService {@Autowiredprivate Pay pay;//这个是你你们本地的订单service,你们可以删除@Autowiredprivate Orderservice orderservice;//这个是你你们本地的订单service,你们可以删除@Autowiredprivate CoreUserService userService;public ResResult goWeChatPay(String money,String des, HttpServletRequest request) throws Exception {//new一个微信支付,实际开发中最好使用单例模式WXPay wxPay = new WXPay(pay);//订单实体,和你们的不同,你们自己换,我使用的是jpa,id是uaa自增长,我这样写的目的是//在下边能使用订单的id做一些事Orders order=new Orders();order.setCoreUser(user);order=orderservice.save(order);String outTradeNo= order.getId().replaceAll("-","0").substring(5);LocalDateTime time_start= LocalDateTime.now();String substring = time_start.toString().substring(0, time_start.toString().lastIndexOf("."));substring=substring.replaceAll("-","").replaceAll("T","").replaceAll(":","").substring(0,14);Map<String, String> params = new HashMap<String, String>();params.put("notify_url", pay.getNotifyUrl());params.put("device_info",pay.getDeviceInfo());params.put("total_fee", String.valueOf(money));params.put("trade_type",pay.getTradeType());params.put("body", des);//商品描述params.put("openid", user.getOpenId());params.put("out_trade_no", outTradeNo);params.put("spbill_create_ip", GetRealyIp.getIPAddress(request));params.put("time_start",String.valueOf(Long.parseLong(substring)));//加上下边这个东西好像报错,报一个啥啥一分钟,啥啥其他不能低于5分钟,忘记了,你们自行研究,//这里我是没搞好的,你们谁搞好了帮忙通知一哈我(微信:gdc1997i),谢谢
//        long expire = Long.parseLong(substring)+240;
//        params.put("time_expire", String.valueOf(expire));//这下边也是我的订单实体的,你们自己换成你们自己的order.setWxOutTradeNo(outTradeNo);order.setOrderName(des);orderservice.save(order);System.out.println("out_trade_no:"+ outTradeNo);System.out.println("time_start:"+Long.parseLong(substring));Map<String, String> resultMap = null;try {resultMap = wxPay.unifiedOrder(params);} catch (Exception e) {e.printStackTrace();}System.out.println("--------------------------------------------------------------------------------");System.out.println("return_code:"+resultMap.get("result_code"));System.out.println("result_code:"+resultMap.get("result_code"));System.out.println("appid:"+resultMap.get("appid"));System.out.println("mch_id:"+resultMap.get("mch_id"));System.out.println("device_info:"+resultMap.get("device_info"));System.out.println("nonce_str:"+resultMap.get("nonce_str"));System.out.println("sign:"+resultMap.get("sign"));System.out.println("err_code:"+resultMap.get("err_code"));System.out.println("err_code_des:"+resultMap.get("err_code_des"));System.out.println("--------------------------------------------------------------------------------");if ("FAIL".equals(resultMap.get("return_code"))) {//这里,我是如果预下单不成功,就删除刚才新建的orderorderservice.delete(order);System.out.println("FAIL");return new ResResult().err(500,resultMap);}else if ("SUCCESS".equals(resultMap.get("result_code"))) {System.out.println("trade_type:"+resultMap.get("trade_type"));System.out.println("prepay_id:"+resultMap.get("prepay_id"));System.out.println("code_url:"+resultMap.get("code_url"));Map<String,String> map=new HashMap<>();map.put("appId",resultMap.get("appid"));//微信那边要求时间戳只能是十位,我这样干估计有问题,但现在还没遇到,哈哈哈!String time = String.valueOf(System.currentTimeMillis()).substring(0,10);System.out.println("timeStamp:"+time);map.put("timeStamp",new Date().toString());map.put("nonceStr",WXPayUtil.generateNonceStr());map.put("package","prepay_id="+resultMap.get("prepay_id"));//加密方式和之前预下单的一样,预下单没看见传这个是因为它封装好了的,//可以从下单的那个方法跟着代码就能看见map.put("signType","MD5");String sing=WXPayUtil.generateSignature(map,pay.getKey());map.put("paySign",sing);//这里返回给前端return new ResResult().ok().data(map);}return null;}//这个支付成功是返回通知@Overridepublic String reply(HttpServletRequest request, HttpServletResponse response) throws IOException {String res = "";InputStream inputStream = request.getInputStream();BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, UTF8));StringBuffer stringBuffer = new StringBuffer();String line = null;while((line = bufferedReader.readLine()) != null) {stringBuffer.append(line);}String xml = stringBuffer.toString();//System.out.println("微信支付成功,微信发送的callback信息,请注意修改订单信息");InputStream is = null;try {is = request.getInputStream();//获取请求的流信息(这里是微信发的xml格式所有只能使用流来读)String RETURN_CODE = "return_code";Map<String, String> notifyMap = WXPayUtil.xmlToMap(xml);//将微信发的xml转mapif(notifyMap.get("return_code").equals("SUCCESS")){if(notifyMap.get("result_code").equals("SUCCESS")){//商户订单号String ordersSn = notifyMap.get("out_trade_no");//实际支付的订单金额:单位 分String amountpaid = notifyMap.get("total_fee");//将分转换成元-实际支付金额:元BigDecimal amountPay = (new BigDecimal(amountpaid).divide(new BigDecimal("100"))).setScale(2);//如果有需要可以获取String openid = notifyMap.get("openid");String trade_type = notifyMap.get("trade_type");/*以下是自己的业务处理------仅做参考* 更新order对应字段/已支付金额/状态码*/}}//告诉微信服务器收到信息了,不要在调用回调action了//========这里很重要回复微信服务器信息用流发送一个xml即可res= "<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>";response.getWriter().write(res);is.close();} catch (Exception e) {e.printStackTrace();}return res;}
}

controller(WeichatPayController )

@RestController
@RequestMapping("pay")
public class WeichatPayController {@Autowiredprivate WechatPayService wechatPayService;@RequestMapping("/wechatpay")public ResResult wxUnifiedorder(@RequestParam("money") String money,@RequestParam("des") String des, HttpServletRequest request) throws Exception {return wechatPayService.goWeChatPay(money,des, request) ;}@RequestMapping("hasOrder")public String  reply(HttpServletRequest request,HttpServletResponse response) throws Exception {response.getWriter().write( wechatPayService.reply(request, response));return "<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>";}
}

前端(我这里是没有前后端分离,引擎使用的是thymeleaf)

终于到最后一步了html,新建一个pay.html

pay.html的位置不必和我的一样,但方式一定一样,内容我就不全写了,把重要的部分干出来
immediateRecharge()这个函数就是你点击需要支付产品的时候出发的函数,它就会调起微信的h5支付页面

//这个必须要加载你的html那<script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js" type="text/javascript"></script><script type="text/javascript">function addMoney(money) {$("#money").text(money);}var appId,timeStamp,nonceStr,package,signType,paySign;function immediateRecharge(){//money=9990不能是小数必须是整数,它那边还要化成元,基本单位是分,这个只是题外的话,不管他了var url="/pay/wechatpay?money=9990&des=佐良科技-会员"$.get(url,function(result) {if (result.data.code==200){appId = result.data.appId;timeStamp = result.data.timeStamp;nonceStr = result.data.nonceStr;package = result.data.package;signType = result.data.signType;paySign = result.data.paySign;if (typeof WeixinJSBridge == "undefined") {if (document.addEventListener) {document.addEventListener('WeixinJSBridgeReady',onBridgeReady, false);} else if (document.attachEvent) {document.attachEvent('WeixinJSBridgeReady',onBridgeReady);document.attachEvent('onWeixinJSBridgeReady',onBridgeReady);}} else {onBridgeReady();}}else {alert("服务器错误")}});}function onBridgeReady(){WeixinJSBridge.invoke( 'getBrandWCPayRequest', {"appId":appId, //公众号名称,由商户传入"timeStamp":timeStamp, //时间戳,自1970年以来的秒数"nonceStr":nonceStr, //随机串"package":package,"signType":signType, //微信签名方式:"paySign":paySign //微信签名},function(res){if(res.err_msg == "get_brand_wcpay_request:ok" ) {console.log('支付成功');//支付成功后跳转的页面}else if(res.err_msg == "get_brand_wcpay_request:cancel"){console.log('支付取消');}else if(res.err_msg == "get_brand_wcpay_request:fail"){console.log('支付失败');WeixinJSBridge.call('closeWindow');}//使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。});}
</script>

spring boot微信支付到此结束!

我也是第一次写这个csdn论坛的文章,


http://www.ppmy.cn/news/675366.html

相关文章

关于修改host的一点整理

在和GFW玩耍的道路上尝试了挺多方法&#xff0c;这里仅对上不去的网站进行分析的方法和修改host的方法做一点整理总结&#xff0c;基本的方法和原理网上有很多教程&#xff0c;就不再赘述了&#xff0c;纯属小白的一点小小尝试。 网站被墙的三种状态 原文地址&#xff1a;htt…

Google 镜像站大集合

原文链接&#xff1a;http://blog.csdn.net/zuoyou1314/article/details/45913603 没有了google的日子是相当难受&#xff0c;下面推荐一些google的镜像站&#xff0c;感谢原文博主的无私奉献&#xff0c;同时也欢迎大家总结科研上的小技巧&#xff0c;心得等来本平台投稿&…

oracle一列中间加一个字_「首席看架构」用GoldenGate创建从Oracle到Kafka的CDC事件流...

我们通过GoldenGate技术在Oracle DB和Kafka代理之间创建集成&#xff0c;该技术实时发布Kafka中的CDC事件流。 Oracle在其Oracle GoldenGate for Big Data套件中提供了一个Kafka连接处理程序&#xff0c;用于将CDC(更改数据捕获)事件流推送到Apache Kafka集群。 因此&#xff0…

oracle oci.dll无法加载_基于OGG 实现Oracle到Kafka增量数据实时同步

背景 在大数据时代&#xff0c;存在大量基于数据的业务。数据需要在不同的系统之间流动、整合。通常&#xff0c;核心业务系统的数据存在OLTP数据库系统中&#xff0c;其它业务系统需要获取OLTP系统中的数据。传统的数仓通过批量数据同步的方式&#xff0c;定期从OLTP系统中抽取…

lol最克制诺手的英雄_LOL:对线很“无解”的5个英雄,其实他们都有克星,诺手只怕它!...

在英雄联盟中如果在对线阶段就崩盘的话&#xff0c;那后面的游戏也会很难玩&#xff0c;而在LOL每个位置上都有些对线比较强的英雄&#xff0c;导致很多玩家会觉得他们“对线无解”&#xff0c;感觉选什么都打不过&#xff0c;排位遇到对手选出这些“无解英雄”的时候就非常害怕…

lnmp架构mysql500是什么原因_LNMP架构介绍

LNMP架构 LNMP架构介绍 1)使前端web服务和后端存储服务进行串联 2)主要实现处理PHP程序动态请求 LNMP的工作原理 LNMP: L:表示linux N:表示Nginx M&#xff1a;表示mysql P:表示PHP 工作原理&#xff1a; 前端接收用户的请求&#xff0c;到达nginx后&#xff0c;nginx服务会先判…

python自学-class24-进程线程练习Plus

进程线程练习Plus 1. 数据检索多进程 2. 求东方财富平均市值 3. 多线程统计平均市值 4. 多进程统计平均市值 5. 单线程爬取邮箱 6. 多线程爬取邮箱 7. 多线程简单文件归并 8. 多线程文件归并—多个文件交叉写入 1.数据检索多进程 昨天写了一个多线程的&#xff0c;逻辑差不太…

python自学-class19(down)-学习爬虫基础

1.读取网页(俩种方式&#xff0c;按行读与全部读) import urllib.request #请求#一次全部读取网页源码 #mystr urllib.request.urlopen("http://www.baidu.com").read() #print(mystr.decode("utf-8")) #按行读取 for line in urllib.request.urlopen(&…