Java、JSAPI、 ssm架构 微信支付demo

1.前端 index.html

java 复制代码
<%@page import="com.tenpay.configure.WxPayConfig"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
	
	<style>
	#fukuan{
	  font-size: 50px;
	   margin-top: 450px;
	}
	.amount{
		width: 400px;
	    height: 80px;
	    font-size: 50px;
	    text-align: center;
	   
	}

  #shouquan {
    display: inline-block;
    width: 600px;
    height: 120px;
    border-radius: 30px;
    font-size: 55px;
    background-color: #00bbff;
    color: white;
    line-height: 120px;
    margin-top: 100px;
}
</style>
	
	
	<body>
	<div style="text-align: center;margin-top:50px;">
	<h3>
		<!-- redirect_uri:是你自己的,主要要url编码 
			state:可以是任意参数,我一般理解为商品id,你在后台WxPayAction中可以获取到,在到数据库中查询商品详细信息,我写死是1000000
		    scope:  snsapi_userinfo(用户有感知,需用户点击授权)     snsapi_base(默认授权)
		
		-->
		     <div id="fukuan">
		                  付款金额:<input type="text" name="amount"  class="amount">&nbsp;&nbsp;元
	         </div>
		     <h1>
			<div id="shouquan">
			        授权支付
			</div>
		</h1>
	</h3>
	</div>
	</body>

	

</html>
<script type="text/javascript" src="${pageContext.request.contextPath }/resources/jquery-1.9.0.min.js"></script>

 <script type="text/javascript">
 
 $(function(){
		
	 $(document).on("click","#shouquan",function(){	
		 
		//获取选中的单选框元素
		 var price = $("input[name='amount']").val();
		 alert("付款金额====="+price);
		 
		// location="${pageContext.request.contextPath }/alipay_pay_liaotian.html?selectOpenId="+selectOpenId; 
		    
		 location="https://open.weixin.qq.com/connect/oauth2/authorize?appid=<%=WxPayConfig.APP_ID %>&redirect_uri=<%=WxPayConfig.REDIRECT_URI %>&response_type=code&scope=snsapi_userinfo&state="+price+"#wechat_redirect";	
	 
	 })
	
	
})
 
 </script>

2.前端 pay.html

java 复制代码
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<%
	String appId = (String)request.getAttribute("appId");
	String timeStamp = (String)request.getAttribute("timeStamp");
	String nonceStr = (String)request.getAttribute("nonceStr");
	String _package = (String)request.getAttribute("package");
	String signType = (String)request.getAttribute("signType");
	String paySign = (String)request.getAttribute("paySign");
	String totalFee = (String)request.getAttribute("totalFee");
%>
<script type="text/javascript">
function callpay()
{
	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();
	    }
}

function onBridgeReady() {
	
	alert("appId=<%=appId %>,timeStamp=<%=timeStamp %>,nonceStr=<%=nonceStr %>,package=<%=_package %>,signType=<%=signType %>,paySign=<%=paySign %>");
	
    WeixinJSBridge.invoke('getBrandWCPayRequest', {
      "appId" : "<%=appId %>",
      "timeStamp" : "<%=timeStamp %>",
      "nonceStr" : "<%=nonceStr %>",
      "package" : "<%=_package %>",
      "signType" : "<%=signType %>",
      "paySign" : "<%=paySign %>"
    }, function(res) { // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回  ok,但并不保证它绝对可靠。  
      //alert(res.err_msg);
      if (res.err_msg == "get_brand_wcpay_request:ok") {
        //alert("支付成功");
        //支付成功,返回首页
        location="https://www.appbi.com/wechat/"; 
		 
      }
      if (res.err_msg == "get_brand_wcpay_request:cancel") {
        alert("交易取消");
      }
      if (res.err_msg == "get_brand_wcpay_request:fail") {
        alert("支付失败");
      }
    });
  }
</script>
</head>
<style>
	#price{
	
		width:100%;
		font-size: 50px;
		text-align: center;
		margin-top: 400px;
	    margin-bottom: 100px;
	    
	}

</style>
<body>
     <div id="price"><span style="font-size: 50px;color:red;font-weight: 900;"><%=totalFee %></span> &nbsp;&nbsp;元 </div>
	 <div style="text-align: center;margin-top: 50px;"><h1><button type="button" style="display:inline-block;width:600px;height:200px;border-radius:30px; background-color: #00bbff;font-size:50px" onclick="callpay()">确认支付</button></h1></div>
</body>
</html>

3. 前端 notify.html

java 复制代码
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>恭喜你,支付成功</title>
</head>
<body>
	<div style="text-align:center;">
		<h1>...恭喜你,支付成功...</h1>
		<h3><a href="https://www.appbi.com/wechat/">跳回首页</a></h3>
	</div>
</body>
</html>

4.后台配置

java 复制代码
package com.tenpay.configure;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

public class WxPayConfig {
	// appid
	public static String APP_ID = "wx9b4ab423461b9";
	// JSAPI接口中获取APP_SECRET,审核后在公众平台开启开发模式后可查看
	public static String APP_SECRET = "668d58d15703cf09d3ad8da996";
	// 受理商ID,身份标识
	public static String MCH_ID = "16079885";
	// 商户支付密钥Key,装完整数后,配置得到。
	public static String KEY = "shanghaishuzikeji123456";
	// 异步回调地址
	//public static String NOTIFY_URL = "http://www.appbi.com/wechat/v_3/notify";
	public static String NOTIFY_URL = "https://www.appbi.com/wechat/v_3/notify.html";
	// 字符编码
	public static String CHARTSET = "UTF-8";
	// 加密方式
	public static String SIGN_TYPE = "MD5";
	// redirect_uri,微信授权重定向地址
	public static String REDIRECT_URI;
	
	static {
		
		try {
			REDIRECT_URI = URLEncoder.encode("http://www.appbi.com/wechat/v_3/pay", CHARTSET);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	}
}

5.后台业务逻辑

java 复制代码
package com.tenpay.action;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jdom2.JDOMException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.tenpay.RequestHandler;
import com.tenpay.configure.WxPayConfig;
import com.tenpay.service.ServiceUtil;
import com.tenpay.util.MD5Util;
import com.tenpay.util.Sha1Util;
import com.tenpay.util.XMLUtil;

import net.sf.json.JSONObject;

/*******************************************************************************
 * <b>类名: WxPayAction.java</b> <br/>
 * 功能:微信支付,调用jsapi<br/>
 * 日期:2015-12-29<br/>
 * 
 * @author <a href="mailto:406224709@qq.com">zhongming</a>
 * @version 1.0
 * 
 ******************************************************************************/
@Controller
@RequestMapping("/v_3")
public class WxPayAction {
	
	/**
	 * 微信客户端授权成功后根据redirect_uri参数调整到pay接口,去准备支付前信息接口
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("pay")
	public String order(HttpServletRequest request, HttpServletResponse response,
			@RequestParam(value="code",required=false) String code,
			@RequestParam(value="state",required=false) Double state
			) throws Exception {
		/**
		 * 第一步:用户同意授权,根据参数,获取code
		 * 授权成功后返回的授权码,参考:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html#.E7.AC.AC.E4.B8.80.E6.AD.A5.EF.BC.9A.E7.94.A8.E6.88.B7.E5.90.8C.E6.84.8F.E6.8E.88.E6.9D.83.EF.BC.8C.E8.8E.B7.E5.8F.96code
		 */
		//String code = request.getParameter("code");
		//String state = request.getParameter("state");
		
		// state可以为任何含义,根据你前端需求,这里暂时叫商品id
		// 授权码、商品id
		System.out.println("code=" + code + ",state=" + state);
		
		/**
		 * 第二步:通过code换取网页授权access_token
		 * 根据授权码code获取access_token,参考:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html#.E7.AC.AC.E4.BA.8C.E6.AD.A5.EF.BC.9A.E9.80.9A.E8.BF.87code.E6.8D.A2.E5.8F.96.E7.BD.91.E9.A1.B5.E6.8E.88.E6.9D.83access_token
		 */
		// 下面就到了获取openid,这个代表用户id.
		// 获取openID
		String openid = ServiceUtil.getOpenId(code);
		// 生成随机字符串
		String noncestr = Sha1Util.getNonceStr();
		// 生成1970年到现在的秒数.
		String timestamp = Sha1Util.getTimeStamp();
		// 订单号,自定义生成规则,只要全局唯一就OK
		String out_trade_no = "NO" + System.currentTimeMillis() + "0001";
		// 订单金额,应该是根据state(商品id)从数据库中查询出来
		//String order_price = String.valueOf(1);
		//state乘100的原因是价格是按分运算   换算成   按元计算
		
		BigDecimal a1 = new BigDecimal(String.valueOf(state));
		BigDecimal b1 = new BigDecimal(String.valueOf(100));
		Integer resultState = a1.multiply(b1).intValue();// double相乘100的方法
		String order_price = String.valueOf(resultState);
		// 商品描述,应该是根据state(商品id)从数据库中查询出来
		String body = "商品描述,测试....";
		
		/**
		 * 第三步:统一下单接口
		 * 需要第二步生成的openid,参考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
		 */
		RequestHandler reqHandler = new RequestHandler(request, response);
		// 初始化 RequestHandler 类可以在微信的文档中找到.还有相关工具类
		reqHandler.init();
		// 执行统一下单接口 获得预支付id,一下是必填参数
		
		// 微信分配的公众账号ID(企业号corpid即为此appId)
		reqHandler.setParameter("appid", WxPayConfig.APP_ID); 
		// 微信支付分配的商户号
		reqHandler.setParameter("mch_id", WxPayConfig.MCH_ID); 
		// 终端设备号(门店号或收银设备ID),注意:PC网页或公众号内支付请传"WEB"
		reqHandler.setParameter("device_info", "WEB"); 
		// 随机字符串,不长于32位。推荐随机数生成算法
		reqHandler.setParameter("nonce_str", noncestr); 
		// 商品描述
		reqHandler.setParameter("body", body); 
		// 商家订单号
		reqHandler.setParameter("out_trade_no", out_trade_no); 
		// 商品金额,以分为单位
		reqHandler.setParameter("total_fee", order_price); 
		// APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。
		reqHandler.setParameter("spbill_create_ip", "123.57.58.123"); 
		// 下面的notify_url是用户支付成功后为微信调用的action 异步回调.
		reqHandler.setParameter("notify_url", WxPayConfig.NOTIFY_URL);
		// 交易类型,取值如下:JSAPI,NATIVE,APP,详细说明见参数规定
		reqHandler.setParameter("trade_type", "JSAPI");
		// ------------需要进行用户授权获取用户openid-------------
		reqHandler.setParameter("openid", openid); // 这个必填.
		/*
		 * <xml><appid>wx2421b1c4370ec43b</appid><attach>支付测试</attach><body>
		 * JSAPI支付测试</body><mch_id>10000100</mch_id><nonce_str>
		 * 1add1a30ac87aa2db72f57a2375d8fec</nonce_str><notify_url>http://wxpay.
		 * weixin.qq.com/pub_v2/pay/notify.v2.php</notify_url><openid>
		 * oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid><out_trade_no>1415659990</
		 * out_trade_no><spbill_create_ip>14.23.150.211</spbill_create_ip><
		 * total_fee>1</total_fee><trade_type>JSAPI</trade_type><sign>
		 * 0CB01533B8C1EF103065174F50BCA001</sign></xml>
		 */
		// 生成签名,并且转为xml
		String requestXml = reqHandler.getRequestXml();
		System.out.println("requestXml:" + requestXml);

		// 得到的预支付id
		String prepay_id = ServiceUtil.unifiedorder(requestXml);
		
		SortedMap<String, String> params = new TreeMap<String, String>();
		params.put("appId", WxPayConfig.APP_ID);
		params.put("timeStamp", timestamp);
		params.put("nonceStr", noncestr);
		params.put("package", "prepay_id=" + prepay_id);
		params.put("signType", "MD5");

		System.out.println("params:" + JSONObject.fromObject(params).toString());
		
		// 生成支付签名,这个签名 给 微信支付的调用使用
		SortedMap<Object,Object> signMap = new TreeMap<Object,Object>();
        signMap.put("appId", WxPayConfig.APP_ID); 
        signMap.put("timeStamp", timestamp);
        signMap.put("nonceStr", noncestr);
        signMap.put("package", "prepay_id=" + prepay_id);
        signMap.put("signType", "MD5");

        
        
        // 微信支付签名
        String paySign = MD5Util.createSign(signMap, WxPayConfig.KEY);
        System.out.println("PaySIGN:" + paySign);
        
		//微信分配的公众账号ID(企业号corpid即为此appId)
		request.setAttribute("appId", WxPayConfig.APP_ID);
		// 时间戳
		request.setAttribute("timeStamp", timestamp); 
		// 随机字符串
		request.setAttribute("nonceStr", noncestr); 
		// 预支付id ,就这样的格式
		request.setAttribute("package", "prepay_id=" + prepay_id);
		// 加密格式
		request.setAttribute("signType", WxPayConfig.SIGN_TYPE); 
		// 微信支付签名
		request.setAttribute("paySign", paySign);
		// 商品金额,以元为单位
		request.setAttribute("totalFee", state.toString()); 
		
		return "pay";
	}

	/**
	 * 异步返回
	 */
	@RequestMapping("notify")
	public String notify(HttpServletRequest request, HttpServletResponse response) {
		try {

			InputStream inStream = request.getInputStream();
			ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
			byte[] buffer = new byte[1024];
			int len = 0;
			while ((len = inStream.read(buffer)) != -1) {
				outSteam.write(buffer, 0, len);
			}
			outSteam.close();
			inStream.close();
			String resultStr = new String(outSteam.toByteArray(), WxPayConfig.CHARTSET);
			Map<String, String> resultMap = XMLUtil.doXMLParse(resultStr);
			
			System.out.println("微信回调结果:" + resultMap.toString());
			
			String result_code = resultMap.get("result_code");
			String is_subscribe = resultMap.get("is_subscribe");
			String out_trade_no = resultMap.get("out_trade_no");
			String transaction_id = resultMap.get("transaction_id");
			String sign = resultMap.get("sign");
			String time_end = resultMap.get("time_end");
			String bank_type = resultMap.get("bank_type");
			String return_code = resultMap.get("return_code");
			// 签名验证
//			GenericValue userLogin = delegator.findOne("UserLogin", UtilMisc.toMap("userLoginId", "admin"), false);
			if (return_code.equals("SUCCESS")) {
				// 此处就是你的逻辑代码
				// 修改数据库支付状态
			}
			request.setAttribute("out_trade_no", out_trade_no);
			// 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
			response.getWriter().write(RequestHandler.setXML("SUCCESS", ""));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (JDOMException e) {
			e.printStackTrace();
		}
		return "notify";
	}
}

6. 上述需要源码插件的链接地址

java 复制代码
  项目demo参考: https://download.csdn.net/download/qq_39951524/88146803
相关推荐
全栈独立开发者2 分钟前
点餐系统装上了“DeepSeek大脑”:基于 Spring AI + PgVector 的 RAG 落地指南
java·人工智能·spring
dmonstererer3 分钟前
【k8s设置污点/容忍】
java·容器·kubernetes
super_lzb8 分钟前
mybatis拦截器ParameterHandler详解
java·数据库·spring boot·spring·mybatis
程序之巅10 分钟前
VS code 远程python代码debug
android·java·python
我是Superman丶21 分钟前
【异常】Spring Ai Alibaba 流式输出卡住无响应的问题
java·后端·spring
墨雨晨曦8822 分钟前
Nacos
java
invicinble30 分钟前
seata的认识与实际开发要做的事情
java
乌日尼乐1 小时前
【Java基础整理】Java多线程
java·后端
2501_941870561 小时前
从配置频繁变动到动态配置体系落地的互联网系统工程实践随笔与多语言语法思考
java·前端·python
她说..2 小时前
Spring 核心工具类 AopUtils 超详细全解
java·后端·spring·springboot·spring aop