代码
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 <xml><br>
* <return_code>SUCCESS/FAIL</return_code><br>
* <return_msg>如非空,为错误 原因签名失败参数格式校验错误</return_msg><br>
* </xml>
* @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>