手把手教你--JAVA微信支付(公众号支付JSAPI)

微信支付(JSAPI支付)接入流程 JSAPI支付是指商户通过调用微信支付提供的JSAPI接口,在支付场景中调起微信支付模块完成收款。 阅读详情

自己的第一篇博客,请各位看官海涵!

JAVA开发微信支付-公众号支付/微信浏览器支付(JSAPI)

    写这篇文章的目的有2个,一是自己的项目刚开发完微信支付功能,趁热回个炉温习一下,二也是帮助像我这样对微信支付不熟悉,反复看了多天文档还是一知半解,原理都没摸清,更不要说实现了。本以为网上的微信开发教程会和“java的重写与重载”一样铺天盖地,可搜出来的结果,要么是PHP的教程(微信支付官网推荐就是PHP),要么星星点点就那么几篇,想对比的看看思路都成问题,官网下载的JAVA-SDK-DEMO也恕我技术低下,看的糊里糊涂。等自己开发完的那一刻,才豁然开朗,才知道走通完支付这条路的过程走了多少弯路,我是第一次接触支付,想必大部分能看这篇文章的兄弟也是被微信官方文档给绕的出不来才出此下策,内容有误请指正。好了这回真正的正题了:

步骤一:获取微信支付四大参数

    首先要想支持微信支付,必须拥有两个账号:①微信公众已认证的服务号,并且需要开通微信支付该能(必须是企业才有资格申请,请你找你家产品去申请吧),②微信商户平台账号;这两个账号一个不能少。此处已默认你已有上两个账号。

    此处是账号模板,请参考:

    微信公众平台:账户:con*******om 登录密码 ******

    公众APPID:wx15*********a8

    APPSECEPT : c210***************892d7

    微信商户平台:账户:149**********6742 登录密码:******

    商户ID:14******42

    API密钥:5d5************b35b

其中比较不好找的是商户的API密钥:在商户平台的账户中心下:需要用户自行下载证书及安装,(略)

    至此我们需要的APPID(appid),APPSECEPT(appsecret),商户ID(mch_id),API密钥(paternerKey),四个重要参数已拿到,括号中是我们代码所用的变量名称请提前熟悉。

步骤二:平台配置

1.配置支付目录:商户平台:

    配置此目录是代码中“微信支付”所在页面的地址,可以是目录不一定是全路径-如http://www.wangtao.com/order/-----此一级域名需要ICP备案。

点击添加

 

2.配置授权域名:微信公众平台:

    支付过程需要获取用户openid,必须经过网页授权配置才可以,要不然获取不到openid。

点击设置,按说明设置

步骤三:开发流程:

    微信支付原理(说白了就是调用官方文档的“统一下单”接口,之后将微信服务器返回的参数做个加工后,返回到前台(JSP页面),就OK了。咱们要做的就是想方设法的凑齐统一下单的所有参数“而已”,“而已”,“而已”,这个而已也就是最大的挑战)。所有参数解释请参考:官方文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1;

    咱们只考虑必填参数,其他参数可以就看你的了。

    先来看看所有参数:

其中的必填参数有:

1.        appid APPID (已有)

2.        mch_id 商户ID (已有)

3.        nonce_str 随机字符串

4.        sign 签名

5.        body 所支付的名称

6.        out_trade_no 咱们自己所提供的订单号,需要唯一

7.        total_fee 支付金额

8.        spbill_create_ip IP地址

9.        notify_url 回调地址

10.       trade_type 支付类型

11.       openid 支付人的微信公众号对应的唯一标识

    只要把这11个凑齐就齐活,现在咱们从第3个开始一个一个的获取;在这之前先从官网把公众号支付的sdk下载下来,如图

    主要是用其中的WXPayUtil工具类中的一些方法。当然其他的类我看不懂,要是看懂了,就不至于这么费劲了。

好了开始咱们的取值之旅了:

1.        appid APPID (已有)

2.        mch_id 商户ID (已有)

3.        nonce_str 随机字符串用WXPayUtil中的generateNonceStr()即可,就是生成UUID的方法;

4.        sign 签名 用WXPayUtil中的generateSignature(finalMap<String, String> data, String key)方法,data是将除了sign外,其他10个参数放到map中,key是四大配置参数中的API秘钥(paternerKey)(这里不要着急管它,最后处理它);

5.        body 所支付的名称

6.        out_trade_no 自己后台生成的订单号,只要保证唯一就好:如“2018013000001”

7.        total_fee 支付金额 单位:分,为了测试此值给1,表示支付1分钱

8.        spbill_create_ip IP地址 网上很多ip的方法,自己找,此处测试给“127.0.0.1”

9.        notify_url 回调地址:这是微信支付成功后,微信那边会带着一大堆参数(XML格式)请求这个地址多次,这个地址做我们业务处理如:修改订单状态,赠送积分等。Ps:支付还没成功还想这么远干嘛,最后再说。地址要公网可以访问。

10.    trade_type 支付类型 咱们是公众号支付此处给“JSAPI”

11.    openid 支付人的微信公众号对应的唯一标识,每个人的openid在不同的公众号是不一样的,这11个参数里,最费劲的就是他了,其他的几乎都已经解决,现在开发得到这个参数。

    获得openid的部分内容应该不属于微信支付的范畴,属于微信公众号网页授权的东西,详情请参考微信网页授权:

https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842

获得openid步骤:

第一步:用户同意授权,获取code

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

注意:1. redirect_uri参数:授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理。

2. scope:用snsapi_base 。

    通过此链接可以获取code,可以在一个空页面设置一个a标签,链接至其redirect_uri的地址。点击a标签,即可链接到redirect_uri的地址,并携带code。

<a href="https://open.weixin.qq.com/connect/oauth2/authorize?
appid=wx15c*********&redirect_uri=http%3a%2f%2fwww.***.com%2fpay.jsp&response_type=code&
scope=snsapi_base#wechat_redirect">去支付页面pay.jsp并携带code</a>

第二步:通过code换取网页授权access_token(其实微信支付就没有必要获取access_token了,咱们只要其中openid,不是要用户信息,此步结果已经就含有咱们需要的openid了)

获取code后,请求以下链接获取access_token: https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

上一步的code有了,对于此链接的参数就容易了。可是在页面上如何处理是个问题,我是在pay.jsp页面加载完成后将获取code当做参数传异步到后台,在后台中用http相关类发送get请求(可以自行网上查找)。返回的JSON结果为:

{ "access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",//就是它,只要这个值
"scope":"SCOPE" }

    好了,access_token是有了,不过咱们不关心它,咱们关心的是openid,有了它一就回到咱们“统一下单”接口里,所有的参数已经就位就等发送了。在回顾下11个必填参数:

1.        appid APPID (已有)

2.        mch_id 商户ID (已有)

3.        nonce_str 随机字符串用WXPayUtil中的generateNonceStr()即可,就是生成UUID的方法;

4.        sign 签名 用WXPayUtil中的publicstatic String generateSignature(final Map<String, String> data, Stringkey)方法,data是将除了sign外,其他10个参数放到map中,key是四大配置参数中的API秘钥(paternerKey)(此时可以处理它了,不过其他10个参数都有了,它就easy了,先new一个map,依次put其他10个参数,就可以用generateSignature方法了,得到了sign后,不要忘记再将sign put到只有10个参数的map中,这样才能凑齐最后的第11个参数。准备召唤神龙吧。);

5.        body 所支付的名称

6.        out_trade_no 自己后台生成的订单号,只要保证唯一就好:如“2018013000001”

7.        total_fee 支付金额 单位:分,为了测试此值给1,表示支付1分钱

8.        spbill_create_ip IP地址 网上很多ip的方法,自己找,此处测试给“127.0.0.1”

9.        notify_url 回调地址:这是微信支付成功后,微信那边会带着一大堆参数(XML格式)请求这个地址多次,这个地址做我们业务处理如:修改订单状态,赠送积分等。Ps:支付还没成功还想这么远干嘛,最后再说。地址要公网可以访问。

10.    trade_type 支付类型 咱们是公众号支付此处给“JSAPI”

11.    openid (已有)

    好了,准备工作完成,开始发送POST请求吧,上面提到网上找到的get请求的方法,此处用到post请求的方法,请求微信"统一下单接口https://api.mch.weixin.qq.com/pay/unifiedorder。发送前先用WXPayUtil工具类中的public static String mapToXml(Map<String,String> data)方法将有11个参数的map转成XML格式。发送后会返回String类型的返回值,如果你够幸运的话应该会得到XML的字符串:

<xml>
  <return_code><![CDATA[SUCCESS]]></return_code>
  <return_msg><![CDATA[OK]]></return_msg>
  <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
  <mch_id><![CDATA[10000100]]></mch_id>
  <nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str>
  <openid><![CDATA[oUpF8uMuAJO_M2pxb1Q9zNjWeS6o]]></openid>
  <sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign>
  <result_code><![CDATA[SUCCESS]]></result_code>
  <prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id>
  <trade_type><![CDATA[JSAPI]]></trade_type>
</xml>

    如果你得到了以上的字符串,那么先恭喜你,坚持看到这,说明你的耐心还是不错的,因为“统一下单”接口调用完毕,可是并没有什么实际的效果,因为微信里想出现支付的界面是在前台完成的现在咱们还在后台玩耍,前面提到的我是页面加载完成时异步到后台的,咱们要返回异步的结果了,好了趁热继续吧。“统一下单”这么费劲的完成其实搞那么麻烦,就是为了得到上面红色的prepay_id(丫的,就这么一个参数给咱们搞的都想说***了)。

    先用WXPayUtil类中的public static Map<String, String> xmlToMap(String strXML)方法,将刚才返回的XML格式的字符串转成map(为了方便取值)。map.get(“prepay_id”)就得到了prepay_id的值(比如得到的是:“wx2018…250…9981…666”),记住它,先保留此值。

看看前台都需要接收哪些值吧。

6个参数,咱们还是一个一个分析:

1.        appId:四大参数之一的APPID;

2.        timestamp:时间戳(newDate()即可)

3.        nonceStr:随机字符串,再次用WXPayUtil中的generateNonceStr()即可;

4.        package:就tm是它用到了prepay_id,但是还不是直接取值,还非要固定格式的,值的格式例如:”prepay_id= wx2018…250…9981…666”

5.        signType:写MD5就好

6.        paySign:又来了还是签名算法 ,按照上面的方法,用WXPayUtil中的publicstatic String generateSignature(final Map<String, String> data, Stringkey)方法,data是将除了paySign外,其他5个参数放到map中,key是四大配置参数中的API秘钥(paternerKey),得到了paySign后,不要忘记再将paySign put到只有5个参数的map中,这样才能凑齐最后的第6个参数。);

注意:此处有个小bug,很多人会被坑的很惨,不注意就掉坑里,我是掉进去了,就是最关键的第4个参数package,眼熟不眼熟,这tm是JAVA的关键字,不能用来当变量名。

所有的参数有了,返回给前端的方法有很多,简易用springMVC的@ResponseBody注解,即可将这个有6个参数的map按json格式传给前端。好了,后台工作完成。

    前端的工作就容易多了,格式比较固定因为是微信固定格式,所以直接贴出我的代码,你只要更换触发支付的事件和异步的地址即可.

前端简单来说:1.一个空jsp页面上有个a标签,用来获取code,并跳转到pay.jsp(上面提到过)。

                        2.pay.jsp中需要异步到后台需要带code参数,pay.jsp中页面的地址上带着code,想获取code的方法很多,抛砖引引玉:(定义一个按钮,按钮上绑定一个code的属性值是页面链接的code的值,用EL表达式取的参数值,点击按钮触发点击事件)。

                        3.接收后台传过来值,调用固定方法。

Pay.jsp中内容只有一个”微信支付”的按钮,和js的代码,以下是js内容(获取code方法可以修改),其它内容不要修改

<!—pay.jsp中点击”微信支付”按钮执行pay()方法>

<input id="code"type="button" value="微信支付"onclick="pay()" code="${param.code }"/>
<script type="text/javascript">
var appId,timeStamp,nonceStr,package,signType,paySign;  
 function pay(){
	var code = $("#code").attr("code");//页面链接上的code参数
	if(code){
		var url = "http://异步地址?code="+code+";
	  	$.get(url,function(result) {
  				appId = result.appId;
				timeStamp = result.timeStamp;
				nonceStr = result.nonceStr;
				package = result.package;
				signType = result.signType;
				paySign = result.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>

以下是后台部分

/**
	 * @Description 微信浏览器内微信支付/公众号支付(JSAPI)
	 * @param request
	 * @param code
	 * @return Map
	 */
	@RequestMapping(value="orders", method = RequestMethod.GET)
	@ResponseBody
	public Map orders(HttpServletRequest request,String code) {
		try {
			//页面获取openId接口
			String getopenid_url = https://api.weixin.qq.com/sns/oauth2/access_token;
			String  param= 
"appid="+你appid+"&secret="+你secret+"&code="+code+"&grant_type=authorization_code";
			//向微信服务器发送get请求获取openIdStr
String openIdStr = HttpRequest.sendGet(getopenid_url, param);
			JSONObject json = JSONObject.parseObject(openIdStr);//转成Json格式
			String openId = json.getString("openid");//获取openId
			
			//拼接统一下单地址参数
			Map<String, String> paraMap = new HashMap<String, String>();
			//获取请求ip地址
			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();
		    }
		    if(ip.indexOf(",")!=-1){
		    	String[] ips = ip.split(",");
		    	ip = ips[0].trim();
		    }
			
			paraMap.put("appid", 你appid);  
			paraMap.put("body", "尧舜商城-订单结算");  
			paraMap.put("mch_id", 你mchId);  
			paraMap.put("nonce_str", WXPayUtil.generateNonceStr());  
			paraMap.put("openid", openId);
			paraMap.put("out_trade_no", 你的订单号);//订单号
			paraMap.put("spbill_create_ip", ip);  
			paraMap.put("total_fee",”1”);  
			paraMap.put("trade_type", "JSAPI");  
			paraMap.put("notify_url",www.*******.com/***/**);// 此路径是微信服务器调用支付结果通知路径随意写
			String sign = WXPayUtil.generateSignature(paraMap, paternerKey);
			paraMap.put("sign", sign);
			String xml = WXPayUtil.mapToXml(paraMap);//将所有参数(map)转xml格式
						
			// 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder
			String unifiedorder_url = https://api.mch.weixin.qq.com/pay/unifiedorder;
	
			String xmlStr = HttpRequest.sendPost(unifiedorder_url, xml);//发送post请求"统一下单接口"返回预支付id:prepay_id
			
			//以下内容是返回前端页面的json数据
			String prepay_id = "";//预支付id
			if (xmlStr.indexOf("SUCCESS") != -1) {  
				Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);  
				prepay_id = (String) map.get("prepay_id");  
			}
			Map<String, String> payMap = new HashMap<String, String>();
			payMap.put("appId", appid);  
			payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp()+"");  
			payMap.put("nonceStr", WXPayUtil.generateNonceStr());  
			payMap.put("signType", "MD5");  
			payMap.put("package", "prepay_id=" + prepay_id);  
			String paySign = WXPayUtil.generateSignature(payMap, paternerKey);  
			payMap.put("paySign", paySign);
			return payMap;
		} catch (Exception e) {  
			e.printStackTrace();
		}  
		return null;
	}

 

以下是网上找的一个发送get和post的类.仅供参考:提前导入相关jar包可网上查找(很容易)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;

public class HttpRequest {
    /**
     * 向指定URL发送GET方法的请求
     * 
     * @param url
     *            发送请求的URL
     * @param param
     *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return URL 所代表远程资源的响应结果
     */
    public static String sendGet(String url, String param) {
        String result = "";
        BufferedReader in = null;
        try {
            String urlNameString = url + "?" + param;
            System.out.println(urlNameString);
            URL realUrl = new URL(urlNameString);
            // 打开和URL之间的连接
            URLConnection connection = realUrl.openConnection();
            // 设置通用的请求属性
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 建立实际的连接
            connection.connect();
            // 获取所有响应头字段
            Map<String, List<String>> map = connection.getHeaderFields();
            // 遍历所有的响应头字段
            for (String key : map.keySet()) {
                System.out.println(key + "--->" + map.get(key));
            }
            // 定义 BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(
                    connection.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送GET请求出现异常!" + e);
            e.printStackTrace();
        }
        // 使用finally块来关闭输入流
        finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 向指定 URL 发送POST方法的请求
     * 
     * @param url
     *            发送请求的 URL
     * @param param
     *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendPost(String url, String param) {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // 发送请求参数
            out.print(param);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送 POST 请求出现异常!"+e);
            e.printStackTrace();
        }
        //使用finally块来关闭输出流、输入流
        finally{
            try{
                if(out!=null){
                    out.close();
                }
                if(in!=null){
                    in.close();
                }
            }
            catch(IOException ex){
                ex.printStackTrace();
            }
        }
        return result;
    }    
}

    ----------------------------------------------------------------------------------

以下是微信支付成功后,向自己项目发送请求,自己来做一些业务处理。

/**
 * @ClassName WxPayController
 * @Description 微信支付成功后回调次接口
 * @author wtao wangtao@eyaoshun.com
 * @date 2018年1月11日 下午3:10:59
 */
//回调路径是自己在之前已经填写过的
@RequestMapping("/pay/")
@Controller
public class WxPayController {
	@Autowired
	private OrdersService ordersService;
	@Autowired
	private AccountService accountService;
	@Autowired
	private PointService pointService;
	
	@RequestMapping("callback")
	public String callBack(HttpServletRequest request,HttpServletResponse response){
		//System.out.println("微信支付成功,微信发送的callback信息,请注意修改订单信息");
		InputStream is = null;
		try {
			is = request.getInputStream();//获取请求的流信息(这里是微信发的xml格式所有只能使用流来读)
			String xml = WXPayUtil.inputStream2String(is, "UTF-8");
			Map<String, String> notifyMap = WXPayUtil.xmlToMap(xml);//将微信发的xml转map
						
			if(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对应字段/已支付金额/状态码
	                 */
	                Orders order = ordersService.selectOrdersBySn(ordersSn);
	                if(order != null) {
	                	order.setLastmodifieddate(new Date());
	                	order.setVersion(order.getVersion().add(BigDecimal.ONE));
	                	order.setAmountpaid(amountPay);//已支付金额
	                	order.setStatus(2L);//修改订单状态为待发货
	                	int num = ordersService.updateOrders(order);//更新order
	                	
	                	String amount = amountPay.setScale(0, BigDecimal.ROUND_FLOOR).toString();//实际支付金额向下取整-123.23--123
	                	/*
	                	 * 更新用户经验值
	                	 */
	                	Member member = accountService.findObjectById(order.getMemberId());
	                	accountService.updateMemberByGrowth(amount, member);
	                	
	                	/*
	                	 * 添加用户积分数及添加积分记录表记录
	                	 */
	                	pointService.updateMemberPointAndLog(amount, member, "购买商品,订单号为:"+ordersSn);
	                	
	                }
	                  
	            }  
	        }
			
	        //告诉微信服务器收到信息了,不要在调用回调action了========这里很重要回复微信服务器信息用流发送一个xml即可
	        response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");  
			is.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}

 

    以上纯手写,如有疏漏请联系,请大神勿喷.谢谢,以上是公众号支付(在微信里),有时间的话我再写一个H5页面的微信支付,请期待.

 

微信支付H5和JSAPI s: 证书序列号,在 账户中心 ▶ API安全 ▶ 管理证书 中可以看见,如果有多个证书,找到自己正在使用的证书序列号。-f: 微信商户API私钥文件目录,也就是第二步申请商户证书里面生成的 apiclient_key.pem 路径。原著:https://www.cnblogs.com/tinygeeker/p/17620498.html。平台证书跟上面申请的商户证书不是同一个东西,在后期请求中,平台证书和商户证书都要带上。-k: apiv3 秘钥,上面自己设置的32位数的密钥。 阅读详情

相关推荐

服务端微信支付(APP和JSAPI支付)相关问题

服务端微信支付相关问题 JSAPI开发文档 jsapi开发文档链接 app开发文档链接 统一下单参数 在开发前需要先申请商户平台申请商户号和APP支付(在开放平台申请账号)、JSAPI(在公众平台申请账号) 在开发过程中先后集成了APP支付和公众号支付(JSAPI支付)此两种支付方式统一下单的参数不同,详见下方: 共同参数: mch_id:商户号;nonce_str:随机字符串;body:商品描...

songjuguang的博客 2900

〔支付接入〕微信的 h5 支付和 jsapi 支付

学会微信支付,打开你的财富之门

国内某知名游戏公司小菜鸡工程师 9550

java微信支付V3(JSAPI支付)前后端代码(uniapp)

java - uniapp 微信支付V3(JSAPI支付)前后端代码

weixin_45729937的博客 2364

微信公众号-JSAPI支付(保姆级教程)

微信公众号-JSAPI支付

qq_43890604的博客 2万+

微信公众号支付(JSAPI)

微信公众号支付(JSAPI),JSAPI,JSAPI支付,appid ,mch_id,nonce_str ,sign,body,out_trade_no,total_fee,spbill_create_ip ,notify_url ,trade_type,openid,WeixinJSBridge.invoke,微信支付模块

江拥羡橙的博客 1万+

【Java必备技能五】微信支付之JSAPI方式(公众号支付)超详细实现步骤

一、JSAPI支付概述 微信官方提供了很多种支付方式,如扫码支付、JSAPI支付、H5支付、NATIVE支付等等,支付接入文档地址:https://pay.weixin.qq.com/wiki/doc/api/index.html。在这几种支付方式中,JSAPI支付应该是稍微复杂点的支付,配置以及流程相对复杂,本文总结一下JSAPI支付的详细实现步骤。 JSAPI支付是用户在微信中打开商户的H5页面,商户在H5页面通过调用微信支付提供的JSAPI接口调起微信支付模块完成支付。应用场景有: ◆ 用户在微信

weixiaohuai的博客 3384

微信支付之JSAPI支付

微信支付之jsapi支付

wg666888的博客 5791

【UE 反射】反射的原理是什么?如何使用机制?

静态类型检查确保了类型的早期一致性和高效的代码执行,但减少了灵活性。动态类型检查提供了更大的灵活性,但增加了运行时的开销和潜在的错误。反射作为一种动态特性,无论是在静态类型语言还是动态类型语言中,都提供了强大的运行时类型操作能力,但也伴随着性能和安全性方面的权衡。通过理解这些联系,开发者可以在不同的编程语言和应用场景中选择适合的类型检查方式和反射机制,以实现所需的动态行为和灵活性,同时保证性能和安全性。

hhw_hhw的博客 6034

H5网站接入微信支付(H5支付+JSAPI支付)

最近开发H5项目,需要接入微信支付,这里记录一下。 场景 项目是 H5 项目,这里踩坑了,以为接入 H5 支付就可以了,后面发现 H5 支付只能在微信外调用,所以后面连忙加入 JSAPI 支付 H5支付 H5支付是指商户在微信客户端外的移动端网页展示商品或服务,用户在前述页面确认使用微信支付时,商户发起本服务呼起微信客户端...

砷碲 - Shendi 1万+

Coze知识库搭建:智能化管理与高效检索实践

知识管理系统是现代企业信息资产管理的核心基础设施,其核心原理是通过结构化存储和智能检索技术实现知识的快速流转。在技术实现上,基于NLP的语义理解引擎和知识图谱构建是关键,能够显著提升检索准确率和知识关联性。以Coze平台为例,其针对中文场景优化的分词算法和多模态处理能力,可有效解决技术文档管理中的术语识别和格式兼容问题。这类系统在开发团队知识沉淀、新员工培训等场景中价值显著,特别是当集成RBAC权限模型和自动化备份策略后,既能保障信息安全,又能实现持续的知识迭代。通过合理配置同义词扩展和权重调整,可使搜索命

weixin_29041195的博客 262

手把手教你用三菱PLC控制JET伺服原点:从硬件接线到GXWORKS3程序调试

本文详细介绍了如何使用三菱PLC控制JET伺服系统实现原点回归功能,涵盖硬件接线、参数配置到GX Works3程序调试的全流程。通过实战指南,帮助工程师快速掌握伺服控制技术,提升工业自动化项目的实施效率。

weixin_30642561的博客 535

JAVA开发微信支付(JSAPI支付)

最近开发完了微信支付功能模块,下面就趁热打铁整理下微信支付(JSAPI支付)相关的知识。 1、JSAPI支付 JSAPI支付是用户在微信中打开商户的H5页面,商户在H5页面通过调用微信支付提供的JSAPI接口调起微信支付模块完成支付。应用场景有: (1)用户在微信公众账号内进入商家公众号,打开某个主页面,完成支付 (2)用户的好友在朋友圈、聊天窗口等分享商家页面连接,用户点击链接打开商家页面,完成支付 (3) 将商户页面转换成二维码,用户扫描二维码后在微信浏览器中打开页面后完成支付 微信支付..

明静致远 4867

操作系统知识点汇总(王道)

操作系统不论是就业还是升学都是核心的一门课程,对于大部分工科更是必修课程。本文章是对《王道操作系统》所有知识点的总结笔记,以供大家学习以及在备考期间复习使用。让我们一起把知识往脑子里旋好吗!!!......

S mile0804的博客 5万+

Java 接入APIV3 微信支付 (一) JSAPI下单

Java 接入APIV3版本的微信支付_JSAPI支付/小程序支付

weixin_43879445的博客 5519

深入剖析RDMA Netlink:Linux内核中高效通信的基石

RDMA Netlink:Linux内核中高效通信控制的核心机制 RDMA技术通过绕过内核实现高速数据传输,但其管理控制仍需内核参与。drivers/infiniband/core/netlink.c文件作为RDMA子系统的心脏,构建了用户空间与内核间的高效通信桥梁。该模块采用模块化客户端架构,通过全局数组管理不同类型的RDMA功能,如设备管理、连接服务和链路层操作。从最初的全局锁到细粒度读写锁的演进,展现了Linux内核追求高性能的持续优化。同时,通过条件编译支持新旧内核版本和网络命名空间,体现了稳定性与

数字人生 239

使用 Simulink + Simscape Electrical 对基于VSG控制的背靠背变流器整流侧进行建模与仿真

本文介绍了基于Simulink的直驱风电系统背靠背变流器整流侧虚拟同步发电机(VSG)建模方法。首先阐述了直驱风电系统结构和VSG控制的作用,然后详细指导了模型搭建过程:从创建项目、添加PMSG和变流器模块,到搭建主电路拓扑和实现VSG控制逻辑。重点说明了VSG控制器如何模拟传统同步发电机的特性,并提供了仿真设置和结果分析方法。该模型可用于研究风电系统在不同工况下的响应特性,为新能源发电系统设计提供重要参考。

amy_mhd的博客 180

最详细的微信支付JSAPI完整流程_java版本

要实现微信支付要满足几个条件: 一、有一个服务号,菜单栏里面有微信支付菜单的公众号 二、需要开通商户号

terry711的专栏 5万+

开源推荐:5个最实用的AIGC风格迁移项目

随着人工智能技术的飞速发展,AIGC(人工智能生成内容)领域取得了显著的成果。风格迁移作为AIGC中的一个重要分支,旨在将一种图像的风格应用到另一种图像上,创造出具有独特艺术效果的新图像。本文的目的是为读者推荐5个最实用的AIGC风格迁移开源项目,详细介绍这些项目的技术原理、使用方法和应用场景,帮助读者在实际项目中选择合适的工具进行风格迁移。文章的范围涵盖了这些项目的核心概念、算法原理、数学模型、项目实战以及相关的学习资源和未来发展趋势等方面。

AI 原生应用开发的博客 1705

JAVA-JSAPI微信公众号-微信支付(非常详细)

因为之前有开发微信的经验,所以少走很多弯路,但是不得不提,微信有很多坑,我现在一个一个帮你们填上,让你们不用走弯路,一路畅通无阻,有任何问题,可以 邮箱我:wh_djj@163.com 1.开通微信支付功能 2.安装证书、设置微信支付秘钥 2.1.此秘钥是自己生成,密码随机生成器,选择32位:链接地址: https://suijimimashengcheng.51240.com/ 3.添加支付...

我说我长的不帅,她们说我说谎,还打我。 9532

[Dify] 【实战笔记】优化 Excel 电话簿类知识库检索效果的实战技巧

摘要:文章分析了Dify知识库在处理Excel结构化数据(如电话簿)时出现的检索异常问题,发现主要原因是默认召回多条记录且缺乏精准匹配机制。提出两个核心解决方案:1)优化知识库召回参数,包括调整TopK值、提高关键词权重等;2)设计精准提示词模板,明确约束模型行为范围。通过对比测试验证了优化效果,并给出进阶建议如数据格式转换、输出格式化等。最后针对知识检索类AI应用提供了场景适配建议。

技术小甜甜:传播可落地技术,帮助个人和企业降低解决真实场景问题的成本 368

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

微信支付总结(JSAPI)(V3)(JAVA)

前一阵子做了一个微信支付相关的功能,期间走了不少的弯路。在这里给大家趟趟雷,希望大家能因此受益。在这里,我从头到尾一步步给大家捋顺。

ZX5191的专栏 1万+

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

springboot整合微信支付

微信支付 springboot整合微信支付 java微信支付 SpringSecurity oauth2 安全资源和授权中心 SpringSecurity登录接口自定义返回字段、SpringSecurity手机号密码登录、SpringSecurity免密登录 i18n国际化 微信登录 微信扫一扫

原名又逢乱世。不要放下学习的脚步,毕竟比天天打牌、钓鱼、打游戏更能从内在充实自己。 6467

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Java之微信支付JSAPI-网页支付

微信支付需要 公众号和商户号 ps:这里使用的是JSAPI支付 1.微信支付需要进行申请 2.公众号 网页授权 3.支付授权目录 4.首先需要获取用户的openid 这里使用的是:网页授权获取用户openid 具体而言,网页授权流程分为四步: 引导用户进入授权页面同意授权,获取code 通过code换取网页授权access_token(与基础支持中的access_token不同) 如果需要,开发者可以刷新网页授权access_token,避免过期 通过网页授权access_token和openid获

qq_40286424的博客 6073

手把手教你如何采用服务商模式实现微信支付

本文服务商模式实现微信支付进行详细的讲解,实现过程还是比较复杂,订单支付中涉及到重复提交、幂等性验证、同步+异步的轮询处理等问题将在后续的文章中进行讲解。

qq_43548590的博客 7562
下一篇: 手把手教你--Bootstrap Table表格插件的使用及数据导出(可导出Excel2003及Exce2007)
小流至江河
博客等级 码龄9年 223粉丝 53原创
评论 201
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值