微信支付

微信支付代码

代码

package app.front.api;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.weixin.XmlResult;
import com.foxinmy.weixin4j.payment.WeixinPayProxy;
import com.foxinmy.weixin4j.payment.mch.MchPayRequest;
import com.foxinmy.weixin4j.payment.mch.Order;
import com.foxinmy.weixin4j.util.Consts;
import com.foxinmy.weixin4j.util.IOUtil;
import com.foxinmy.weixin4j.util.StringUtil;
import com.foxinmy.weixin4j.xml.ListsuffixResultDeserializer;
import com.foxinmy.weixin4j.xml.XmlStream;

import app.base.dao.legouser.OrdersDao;
import app.base.dao.legouser.OrdersItemDao;
import app.base.entity.legouser.Orders;
import app.base.entity.legouser.OrdersItem;
import app.base.entity.legouser.User;
import app.base.service.OrderService;
import app.front.UserContext;
import app.front.api.params.WeixinPayParam;
import component.common.msg.Ret;
import component.common.msg.Rets;
import component.common.utils.LOG;
import component.common.utils.PropertyUtil;
import component.common.utils.RequestUtil;

@Controller
@RequestMapping("api/pay")
public class WeixinPayApi {
    
    private static Map<String, Long> orderIdMap = new HashMap<>();
    
    private String notifyUrl = PropertyUtil.getProperty("pay.notifyUrl");
    @Autowired
    WeixinPayProxy weixinPayProxy;
    @Autowired
    OrdersDao ordersDao;
    @Autowired
    OrdersItemDao ordersItemDao;
    @Autowired
    OrderService orderService;

    @RequestMapping(value = "weixinPay")
    public @ResponseBody Ret pay(HttpServletRequest request,
            HttpServletResponse response
            ,@RequestBody WeixinPayParam param) throws WeixinException, ServletException, IOException {
        User user = UserContext.getLoginUser();
        
        Orders busOrder = ordersDao.get(param.getOrderId());
        
        String openId = user.getOpenId();
        String body = this.buildSetName(busOrder);
        String outTradeNo = UUID.randomUUID().toString().replace("-", "");
        orderIdMap.put(outTradeNo, busOrder.getId());
        double totalFee = busOrder.getPayMoney().doubleValue(); // 订单金额 单位元
        String notifyUrl = this.notifyUrl; // 支付成功回调页面
        String createIp = RequestUtil.getClientIP(request);
        String attach = "";
        // 发起一个JS支付请求,这里有个值得注意的地方:微信返回的预交易ID(payRequest.getPrePayId())是有2小时的时效性的,
        //超过2小时将不能重新发起支付,需重新生成一个`outTradeNo`订单号再次调用createJSPayRequest接口。
        //所以这里的`prePayId`有两种解决方案:
        //1、每次发起支付都重新生成`outTradeNo`订单号,然后调用createJSPayRequest接口。
        //2、把`prePayId`缓存起来,然后通过:MchPayRequest payRequest = new JSAPIPayRequest(prePayId,weixinPayProxy.getPayAccount());
        //构建一个`MchPayRequest`支付对象。两种方式都有利有弊,请根据实际需求而定。
        MchPayRequest payRequest = weixinPayProxy.createJSPayRequest(openId, body, outTradeNo, totalFee, notifyUrl, createIp, attach);
        // 将支付JSON串放到request作用域
        request.setAttribute("jspay", payRequest.toRequestString());
        
        //request.getRequestDispatcher("/pay/pay.jsp").forward(request, response);
        return Rets.successData(payRequest.toRequestObject());
    }
    
    private String buildSetName(Orders busOrder) {
        List<OrdersItem> orderItems = ordersItemDao.listByProperty("ordersId", busOrder.getId());
        List<String> ret = new ArrayList<>(orderItems.size());
        for(OrdersItem item : orderItems) {
            ret.add(item.getSetName());
        }
        
        return StringUtils.collectionToCommaDelimitedString(ret);
    }
    
    /**
     * 微信支付成功(前端)时的回调通知
     * 
     * @param inputStream
     *            订单回调
     * @return &ltxml&gt<br>
     *         &ltreturn_code&gtSUCCESS/FAIL&lt/return_code&gt<br>
     *         &ltreturn_msg&gt如非空,为错误 原因签名失败参数格式校验错误&lt/return_msg&gt<br>
     *         &lt/xml&gt
     * @throws IOException 
     * @see <a
     *      href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7">支付结果通知</a>
     */
    @RequestMapping("/weixinNotify")
    @ResponseBody
    public String payNotify(HttpServletRequest request) throws IOException {
        //获取订单信息
        String content = StringUtil.newStringUtf8(IOUtil.toByteArray(request.getInputStream()));
        Order order = ListsuffixResultDeserializer.deserialize(content,
                Order.class);
        LOG.info("jsapi_notify_order_info:{}", order);
        //验证签名
        String sign = order.getSign();
        String valid_sign = weixinPayProxy.getWeixinSignature().sign(order);
        LOG.info("微信签名----->sign={},vaild_sign={}", sign, valid_sign);
        if (!sign.equals(valid_sign)) {
            return XmlStream.toXML(new XmlResult(Consts.FAIL, "签名错误"));
        }
        // TODO 处理业务逻辑,如没有特殊要求可以考虑单独启一个线程去处理自己的业务,对于微信签名过后就可以返回success了。
        LOG.info("支付成功:{}",order);
        
        String outTradeNo = order.getOutTradeNo();
        Long orderId = orderIdMap.get(outTradeNo);
        orderService.paySuccess(orderId);
        orderIdMap.remove(outTradeNo);
        
        // 需要ajax的形式返回给微信,保证返回值能写到ResponseInputStream就行,Spring mvc使用 @ResponseBody注解,Servlet使用HttpServletResponse#getWrite#write
        return XmlStream.toXML(new XmlResult(Consts.SUCCESS, ""));
    }
    
}

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>订单详情</title>
<script src="https://cdn.bootcss.com/jquery/1.12.2/jquery.min.js"></script>
<script type="text/javascript" src="../static/js/common.js"></script>
<style type="text/css">
body{font-size:80px;}
</style>
<script type="text/javascript">

function pay1fen() {
    $.ajax({
          type: 'POST',
          url: '/lego-web/api/pay/weixinPay.do',
          data: JSON.stringify({
              "orderId":1
          }),
          headers: {
              'Authorization': "Bearer " + getJwt(),
          },
          dataType: 'json',
          contentType: "application/json;charset=UTF-8",
          success: function(ret){
              if(ret.code == 0) {
                 var jspay = ret.data;
                //调用微信支付JS接口
                WeixinJSBridge.invoke('getBrandWCPayRequest', jspay, function(res) {
                    if (res.err_msg == 'get_brand_wcpay_request:ok') {
                        // 支付已完成!,注意这里支付完成指的是前端JS发起支付的操作顺利完成,
                        //并不意味着真正的支付成功,强烈建议到支付回调中去校验支付成功与否。
                        alert('支付成功')
                    } else if (res.err_msg == 'get_brand_wcpay_request:fail') {
                        // 支付出现问题,请稍后再试!
                        alert('支付出现问题')
                    } else if (res.err_msg == 'get_brand_wcpay_request:cancel') {
                        // 已取消支付,请重新支付!
                        alert('已取消支付,请重新支付')
                    } else {
                        alert('支付已拒绝')
                        // 支付被拒绝了
                    }
                }); 
              }else { // 如果没有登录
                  alert('支付失败')
              }
          }
          ,error: function(XMLHttpRequest, textStatus, errorThrown) {
              alert(XMLHttpRequest.status);
            }
        });
}

</script>
</head>
<body>
<a href="#" onclick="pay1fen()">支付一分钱</a>
</body>
</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容