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
相关推荐
FIN技术铺2 分钟前
Spring Boot框架Starter组件整理
java·spring boot·后端
小曲程序9 分钟前
vue3 封装request请求
java·前端·typescript·vue
陈王卜26 分钟前
django+boostrap实现发布博客权限控制
java·前端·django
小码的头发丝、27 分钟前
Spring Boot 注解
java·spring boot
java亮小白199732 分钟前
Spring循环依赖如何解决的?
java·后端·spring
飞滕人生TYF38 分钟前
java Queue 详解
java·队列
武子康1 小时前
大数据-230 离线数仓 - ODS层的构建 Hive处理 UDF 与 SerDe 处理 与 当前总结
java·大数据·数据仓库·hive·hadoop·sql·hdfs
武子康1 小时前
大数据-231 离线数仓 - DWS 层、ADS 层的创建 Hive 执行脚本
java·大数据·数据仓库·hive·hadoop·mysql
苏-言1 小时前
Spring IOC实战指南:从零到一的构建过程
java·数据库·spring
界面开发小八哥1 小时前
更高效的Java 23开发,IntelliJ IDEA助力全面升级
java·开发语言·ide·intellij-idea·开发工具