微信支付

微信支付代码

代码

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>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容