微信支付集成之3商户服务器(JAVA)搭建
上节总结了微信支付的整体业务逻辑,这次总结一下我按部就班搭建商户服务器的步骤。这里后台语言用的是JAVA,我的目的是进一步理解并学习微信信支付业务逻辑,就随选了java。其他后台语言开发应该大同小异,具体实现语法和细节可能不同。
首先,由于要搭建JAVA服务器。我们需要有java开发环境(我这里用的IDE是Eclipse),至于配置方法我之前有篇文章可以参考:微信支付集成之1Java环境配置
准备工作
1.打开Eclipse,创建一个新的Dynamic Web项目
图1.1 图1.22.在项目左侧找到WebContent/WEB-INF/lib,添加这几个库:gson,jdom,jsonObject,这都是java开发常用到的几个库,网上都能找到。添加,全选右键Build Path-Add to Build Path,这样才算将用到的库添加到了项目中。
1.3添加后,左侧项目视图里Referenced Librayies下出现了相应的库,说明添加成功。
1.43.准备好从网上下载好的微信支付Java版工具类,这是我下载到的,个人觉得封装得还不错。
1.54.我们知道Java里的源代码在src目录下,所以依次打开到src,右键新建一个Packet命名为com.charos.CHWxPay.Utils
1.6 1.7点击完成后,看左侧的工程目录src下就多了一个Utils的包。
5.将下载的工具包(图1.5)的utils文件拷贝到该包下,然后以同样的方式新建一个http包,同样的方式将工具包内文件拷贝。
此时,发现文件都拷贝过来了,但是会报错。这个错误一般可能是由于文件移动造成寻找路径不对,只需要打开对应文件停留光标到导入文件出:cmd+shift+o 修正文件路径即可。
写用于自己项目的支付类
- 新建一个支付类继承自httpServlet,这是我们自己写的在支付类
2.我们接着在这个类里,写自己项目的支付业务
2.4基本步骤:
第1步-签名订单信息,获取预支付标识
第2步-调用微信统一下单接口
第3步-处理接口返回信息进行二次签名
第4步-将签名信息返回客户端
3.业务代码
在写这里的业务代码前,要配置一下支付服务的基本信息
package com.chaors.CHWxPay;
import java.io.IOException;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.chaors.CHWxPay.Http.bean.OrderResult;
import com.chaors.CHWxPay.Http.bean.OrderResult.OrderBean;
import com.chaors.CHWxPay.Http.impl.PrepayIdRequestHandler;
import com.chaors.CHWxPay.Utils.ConstantUtil;
import com.chaors.CHWxPay.Utils.OrderUtils;
import com.chaors.CHWxPay.Utils.WXUtil;
import com.google.gson.Gson;
//接口名称:WxPayServlet
//接口参数列表
//name:商品名称
//price:商品价格
public class WxPayServlet extends HttpServlet {
// 首先:定义支付应用ID、商户ID等等...
// 应用ID
public static String APP_ID = ConstantUtil.APP_ID;
// 商户ID
public static String PARTNER_ID = ConstantUtil.PARTNER_ID;
// 商户好对应的密钥
public static String PARTNER_KEY = ConstantUtil.PARTNER_KEY;
// 统一下单的接口(微信支付服务器提供的)
public static String URL_UNIFIEDORDER = ConstantUtil.URL_UNIFIEDORDER;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 第1步-签名订单信息
// 第一点:获取客户端传递过来的参数
// req:客户端请求
// resp:响应客户端请求
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
String name = req.getParameter("name");
String price = req.getParameter("price");
// 第二点:设置访问微信支付服务器请求数据类型
resp.reset();
resp.setHeader("ContentType", "text/xml");
// 第三点:创建请求微信支付服务器参数集合
// 做了请求封装
// 微信写好一个封装案例,你可以根据服务器需求,自己定义网络请求框架
PrepayIdRequestHandler handler = new PrepayIdRequestHandler(req, resp);
// 统一下单的接口(调用微信支付服务器需要的接口)--->公开的
handler.setGateUrl(ConstantUtil.URL_UNIFIEDORDER);
// 设置密钥
handler.setKey(PARTNER_KEY);
// 设置应用的ID
handler.setParameter("appid", APP_ID);
// 商户号
handler.setParameter("mch_id", PARTNER_ID);
// 随机字符串
handler.setParameter("nonce_str", WXUtil.getNonceStr());
// 商品描述(APP名-商品名)
handler.setParameter("body", "超哥爱学习-超哥笔记");
// 商户订单号(自己服务器生成订单号)
String out_trade_no = OrderUtils.getOrderNumber();
handler.setParameter("out_trade_no", out_trade_no);
// 总金额
handler.setParameter("total_fee", price);
// 终端IP(客户端IP)
handler.setParameter("spbill_create_ip", req.getRemoteAddr());
// 通知地址(微信服务器回调商户服务器页面)
handler.setParameter("notify_url", ConstantUtil.NOTIFY_URL);
// 交易类型
handler.setParameter("trade_type", "APP");
// 第四点:对我们订单信息进行签名
String sign = handler.createMD5Sign();
// 设置签名
handler.setParameter("sign", sign);
// 第2步-调用微信统一下单接口(目的:获取prepay_id)
// command+1
OrderResult orderResult = new OrderResult();
try {
// 集合参数列表
// 返回结果
// <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>
// <sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign>
// <result_code><![CDATA[SUCCESS]]></result_code>
// <prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id>
// <trade_type><![CDATA[APP]]></trade_type>
// </xml>
Map paramsMap = handler.sendPrepay();
String prepay_id = (String) paramsMap.get("prepay_id");
if (prepay_id != null && !"".equals(prepay_id)) {
// 统一下单接口调用成功
// 第3步-处理接口返回信息进行二次签名
// 调用支付接口:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12&index=2
// 二次签名和一次签名,参数不一样(复用之前参数集合)
// 请求集合列表(情空:不影响新的参数签名)
// 微信服务器要求
handler.clear();
String noncestr = (String) paramsMap.get("noncestr");
String timestamp = WXUtil.getTimeStamp();
// 密钥
handler.setKey(PARTNER_KEY);
// 设置应用的ID
handler.setParameter("appid", APP_ID);
// 预付单ID
handler.setParameter("prepayid", prepay_id);
// 扩展字段
handler.setParameter("package", "Sign=WXPay");
// 商户号
handler.setParameter("partnerid", PARTNER_ID);
// 随机字符串
handler.setParameter("noncestr", noncestr);
// 时间戳
handler.setParameter("timestamp", timestamp);
// 进行二次签名(签名参数不一样)
// 第一次签名:对订单信息签名,获取prepay_id
// 第二次签名:对支付信息进行签名
sign = handler.createMD5Sign();
// 第4步-将签名信息返回客户端(xml、json都可以)
// 采用Json解析(构建json--->返回客户端)
OrderBean orderBean = new OrderBean();
orderBean.setAppid(APP_ID);
orderBean.setNoncestr(noncestr);
orderBean.setPackageValue("Sign=WXPay");
orderBean.setPartnerid(PARTNER_ID);
orderBean.setPrepayid(prepay_id);
orderBean.setTradeType((String) paramsMap.get("trade_type"));
orderBean.setSign(sign);
orderBean.setTimestamp(timestamp);
orderResult.setOrderBean(orderBean);
// 将model转json数据格式(框架)--->服务器开发(bean)
//resultCode:随便你定义(根据服务器要求)
//0:成功 1:失败 2:未知异常
orderResult.setResultCode(0);
orderResult.setResultMessage("获取成功!");
} else {
// 调用失败
orderResult.setResultCode(9);
orderResult.setResultMessage("获取失败!");
}
} catch (Exception e) {
e.printStackTrace();
orderResult.setResultCode(6);
orderResult.setResultMessage("未知异常!");
}
// 将json返回给客户端
Gson gson = new Gson();
String jsonStr = gson.toJson(orderResult);
resp.getWriter().print(jsonStr);
}
}
4.接口配置
首先,从别的项目拷贝一份web.xml文件到WEB-INF下,按下图提示配置。
然后,从别的项目拷贝一份index.jsp文件到WEB-Content下,无需改动即可。
这样,微信支付的商户服务器就基本搭建完成。选择项目,右键Run as Server运行便启动了商户服务器。正常运行,将得到的网址作为客户端提交订单信息的接口:
服务器启动成功可能的问题
1.运行项目出现Tomcat启动失败
3.1这时,选择左上角Eclipse-设置-找Runtime Environments。删除现有的Tomcat服务器,然后新建一个服务器即可。
3.2 3.32.还有可能出现以下问题:
3.4解决方案为:
3.5 3.6终于写完了,我发现总结笔记可比实际项目操作慢多了。得考虑很多方面,不过同时也学到了许多以前忽视的地方。希望能在这条路上走得更远!
晚安,这个世界!
晚安,那些写代码的可爱的人儿!
--20171023凌晨
我们讲述生命,
我们前行,
同时告别它的正在移栖的鸟群,
我们属于最美好的一代人。
-----------------------------诗人 奥德修斯-埃利帝斯