Java服务器端编程iOS学习笔记iOS程序猿

微信支付集成之3商户服务器(JAVA)搭建

2017-10-25  本文已影响35人  WallisW

上节总结了微信支付的整体业务逻辑,这次总结一下我按部就班搭建商户服务器的步骤。这里后台语言用的是JAVA,我的目的是进一步理解并学习微信信支付业务逻辑,就随选了java。其他后台语言开发应该大同小异,具体实现语法和细节可能不同。

首先,由于要搭建JAVA服务器。我们需要有java开发环境(我这里用的IDE是Eclipse),至于配置方法我之前有篇文章可以参考:微信支付集成之1Java环境配置

准备工作

1.打开Eclipse,创建一个新的Dynamic Web项目

图1.1 图1.2

2.在项目左侧找到WebContent/WEB-INF/lib,添加这几个库:gson,jdom,jsonObject,这都是java开发常用到的几个库,网上都能找到。添加,全选右键Build Path-Add to Build Path,这样才算将用到的库添加到了项目中。

1.3

添加后,左侧项目视图里Referenced Librayies下出现了相应的库,说明添加成功。

1.4

3.准备好从网上下载好的微信支付Java版工具类,这是我下载到的,个人觉得封装得还不错。

1.5

4.我们知道Java里的源代码在src目录下,所以依次打开到src,右键新建一个Packet命名为com.charos.CHWxPay.Utils

1.6 1.7

点击完成后,看左侧的工程目录src下就多了一个Utils的包。

5.将下载的工具包(图1.5)的utils文件拷贝到该包下,然后以同样的方式新建一个http包,同样的方式将工具包内文件拷贝。
此时,发现文件都拷贝过来了,但是会报错。这个错误一般可能是由于文件移动造成寻找路径不对,只需要打开对应文件停留光标到导入文件出:cmd+shift+o 修正文件路径即可。

1.8

写用于自己项目的支付类

  1. 新建一个支付类继承自httpServlet,这是我们自己写的在支付类
2.1 2.2 2.3

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下,按下图提示配置。

2.4

然后,从别的项目拷贝一份index.jsp文件到WEB-Content下,无需改动即可。

这样,微信支付的商户服务器就基本搭建完成。选择项目,右键Run as Server运行便启动了商户服务器。正常运行,将得到的网址作为客户端提交订单信息的接口:

服务器启动成功

可能的问题

1.运行项目出现Tomcat启动失败

3.1

这时,选择左上角Eclipse-设置-找Runtime Environments。删除现有的Tomcat服务器,然后新建一个服务器即可。

3.2 3.3

2.还有可能出现以下问题:

3.4

解决方案为:

3.5 3.6

终于写完了,我发现总结笔记可比实际项目操作慢多了。得考虑很多方面,不过同时也学到了许多以前忽视的地方。希望能在这条路上走得更远!

晚安,这个世界!
晚安,那些写代码的可爱的人儿!

--20171023凌晨



我们讲述生命,
我们前行,
同时告别它的正在移栖的鸟群,
我们属于最美好的一代人。
-----------------------------诗人 奥德修斯-埃利帝斯

上一篇下一篇

猜你喜欢

热点阅读