package com.example.controller; import com.alibaba.fastjson.JSON; import com.example.base.*; import com.example.entity.OmsOrder; import com.example.entity.RefundOrder; import com.example.entity.WxPayFrom; import com.example.enums.PayStatusEnum; import com.example.enums.ResultEnum; import com.example.util.GeneratorIdUtils; import com.example.util.RedisUtil; import com.example.util.UUIDUtils; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest; import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult; import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult; import com.github.binarywang.wxpay.constant.WxPayConstants; import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.service.WxPayService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.bean.WxJsapiSignature; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.math.BigDecimal; @Slf4j @RestController @Api(tags = "公众号支付", description = "WechatH5PayController") @RequestMapping("/app") public class WechatH5PayController extends BaseController { private final static String OMSORDER = "oms_order_"; @Value("${wx.pay.wxpayAppcallbackurl}") private String wxpayCallbackUrl; @Value("${wx.pay.wxpayRefundCallBackUrl}") private String wxpayRefundCallBackUrl; @Autowired private WxPayService wxPayService; @Autowired private RedisUtil redisUtil; @PostMapping("/pay") public ResponseBase pay(@RequestBody WxPayFrom wxPayFrom, HttpServletRequest request) { String orderId = wxPayFrom.getOrderId(); String openid = wxPayFrom.getOpenid(); String tradeType = wxPayFrom.getTradeType(); OmsOrder omsOrder = JSON.parseObject(redisUtil.get(OMSORDER + orderId).toString(), OmsOrder.class); Integer status = omsOrder.getStatus(); //查询订单是否支付 if (status.equals(PayStatusEnum.SUCCESS.getIndex())) { throw new RuntimeException("订单已支付"); } WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest(); //随机字符串 String s = UUIDUtils.randomUUID(); orderRequest.setNonceStr(s); //商品描述 String productName = omsOrder.getProductName(); orderRequest.setBody(productName); //商户订单号(支付编号) // GeneratorIdUtils generatorIdUtils = new GeneratorIdUtils(); // String orderNum = generatorIdUtils.nextId(); // log.info("orderNum:" + orderNum); //设置商户订单号 orderRequest.setOutTradeNo(orderId); //设置金额 //data.getTotalPrice(); BigDecimal money = omsOrder.getPayAmount(); //元转成分 money = money.multiply(new BigDecimal(100)); int i = money.intValue(); if ("test".equals(tradeType)) { //测试环境一分钱 orderRequest.setTotalFee(1); } else { orderRequest.setTotalFee(i); } //终端ip String ipAddress = getIpAddress(request); orderRequest.setSpbillCreateIp(ipAddress); // 通知地址 支付成功后回调地址 log.info("wxpayCallbackUrl=================>{}", wxpayCallbackUrl); orderRequest.setNotifyUrl(wxpayCallbackUrl); //交易类型 orderRequest.setTradeType(WxPayConstants.TradeType.JSAPI); //用户标识 获取用户openid orderRequest.setOpenid(openid); // 这个可能是偏向原生一点的统一下单,返回的参数有很多没用的 或者null值 建议使用 createOrder下单 Object unOrder = null; try { unOrder = wxPayService.createOrder(orderRequest); } catch (WxPayException e) { //e.printStackTrace(); log.error(e.getMessage()); //签名完成新增支付订单 return responseError(500, "微信支付失败"); } //更新本地订单支付id //orderClient.update(data); //签名完成新增支付订单 return responseSuccess(new ResultVO(ResultEnum.SUCCESS, unOrder)); } @Autowired private WxMpService wxMpService; /*微信js签名接口*/ @GetMapping("/getJsapiTicket") public ResponseBase getJsapiTicket(String url) { WxJsapiSignature jsapiSignature = null; try { jsapiSignature = wxMpService.createJsapiSignature(url); } catch (WxErrorException e) { e.printStackTrace(); System.err.print(e.getError()); } return responseSuccess(new ResultVO(ResultEnum.SUCCESS, jsapiSignature)); } /** * wx支付成功回调接口 * * @param request * @param response * @throws IOException */ @RequestMapping("/payResult") @ApiOperation("微信支付返回通知") public void payResult(HttpServletRequest request, HttpServletResponse response) throws IOException { log.info("微信支付返回通知函数开始---------------------"); InputStream inStream = request.getInputStream(); ByteArrayOutputStream outSteam = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while ((len = inStream.read(buffer)) != -1) { outSteam.write(buffer, 0, len); } outSteam.close(); inStream.close(); String result = new String(outSteam.toByteArray(), "utf-8"); boolean isPayOk = false; WxPayOrderNotifyResult wxPayOrderNotifyResult = null; // 此处调用订单查询接口验证是否交易成功 try { wxPayOrderNotifyResult = wxPayService.parseOrderNotifyResult(result); if ("SUCCESS".equals(wxPayOrderNotifyResult.getResultCode())) { isPayOk = true; } log.info("解析数据:" + wxPayOrderNotifyResult.toString()); } catch (WxPayException e) { e.printStackTrace(); } String noticeStr = ""; // 支付成功,商户处理后同步返回给微信参数 PrintWriter writer = response.getWriter(); if (isPayOk) { //建议在这里处理付款完成的业务(虽然前端也可以处理后续业务,但是前端处理并不安全,例如:客户突然关闭浏览器了等情况,付款成功后续的业务将中断) //支付订单支付编号 System.out.println("===============付款成功,业务开始处理=============="); String orderNum = wxPayOrderNotifyResult.getOutTradeNo(); log.info("orderNum:" + orderNum); //将订单更新为支付 OmsOrder omsOrder = JSON.parseObject(redisUtil.get(OMSORDER + orderNum).toString(), OmsOrder.class); omsOrder.setStatus(PayStatusEnum.SUCCESS.getIndex()); redisUtil.set(OMSORDER + omsOrder.getOrderId(), omsOrder); /** * 自己的业务 */ System.out.println("===============付款成功,业务处理完毕=============="); // 通知微信已经收到消息,不要再给我发消息了,否则微信会8连击调用本接口 noticeStr = setXML("SUCCESS", "OK"); log.info("收到通知返回给微信api信息:-----------" + noticeStr); writer.write(noticeStr); writer.flush(); } else { // 支付失败, 记录流水失败 noticeStr = setXML("FAIL", ""); writer.write(noticeStr); writer.flush(); System.out.println("===============支付失败=============="); } } public static String setXML(String return_code, String return_msg) { return ""; } public static String getIpAddress(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } String[] split = ip.split(","); ip = split[0]; return ip; } @GetMapping("/order/{orderId}") @ApiOperation("查询订单状态") public ResponseBase queryOrder(@PathVariable(value = "orderId") String orderId) { try { WxPayOrderQueryResult orderQueryResult = wxPayService.queryOrder(null, orderId); return responseSuccess(new ResultVO(ResultEnum.SUCCESS, orderQueryResult)); } catch (WxPayException e) { e.printStackTrace(); return responseError(500, "查询订单异常"); } } @PostMapping("/order/refund") @ApiOperation("申请退款") public ResponseBase refundOrder(@RequestBody RefundOrder refundOrder) { WxPayRefundRequest refundRequest = new WxPayRefundRequest(); try { OmsOrder omsOrder = JSON.parseObject(redisUtil.get(OMSORDER + refundOrder.getOrderId()).toString(), OmsOrder.class); refundRequest.setOutTradeNo(refundOrder.getOrderId()); GeneratorIdUtils generatorIdUtils = new GeneratorIdUtils(); String refundNo = generatorIdUtils.nextId(); refundRequest.setOutRefundNo(refundNo); refundRequest.setRefundDesc(refundOrder.getRefundDesc()); refundRequest.setTotalFee(omsOrder.getTotalAmount().intValue()); refundRequest.setRefundFee(refundRequest.getTotalFee()); refundRequest.setOpUserId(refundRequest.getMchId()); refundRequest.setNotifyUrl(wxpayRefundCallBackUrl); wxPayService.refund(refundRequest); } catch (WxPayException e) { e.printStackTrace(); return responseError(500, "申请退款异常"); } return responseSuccess(new ResultVO()); } @RequestMapping("/refundResult") @ApiOperation("退款回调") public void refundResult(HttpServletRequest request, HttpServletResponse response) throws IOException { log.info("微信退款回调通知函数开始---------------------"); InputStream inStream = request.getInputStream(); ByteArrayOutputStream outSteam = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while ((len = inStream.read(buffer)) != -1) { outSteam.write(buffer, 0, len); } outSteam.close(); inStream.close(); String result = new String(outSteam.toByteArray(), "utf-8"); boolean refundOk = false; WxPayRefundNotifyResult wxPayRefundNotifyResult = null; try { wxPayRefundNotifyResult = wxPayService.parseRefundNotifyResult(result); if ("SUCCESS".equals(wxPayRefundNotifyResult.getReturnCode())) { refundOk = true; } log.info("解析数据:" + wxPayRefundNotifyResult.toString()); } catch (WxPayException e) { e.printStackTrace(); } String noticeStr = ""; // 支付成功,商户处理后同步返回给微信参数 PrintWriter writer = response.getWriter(); if (refundOk) { //建议在这里处理付款完成的业务(虽然前端也可以处理后续业务,但是前端处理并不安全,例如:客户突然关闭浏览器了等情况,付款成功后续的业务将中断) //支付订单支付编号 System.out.println("===============退款成功,业务开始处理=============="); String refundNo = wxPayRefundNotifyResult.getReqInfo().getOutRefundNo(); log.info("refundNo:" + refundNo); //将订单更新已退款 /** * 自己的业务 */ System.out.println("===============退款成功,业务处理完毕=============="); //todo:关闭订单 noticeStr = setXML("SUCCESS", "OK"); log.info("收到通知返回给微信api信息:-----------" + noticeStr); writer.write(noticeStr); writer.flush(); } else { // 支付失败, 记录流水失败 noticeStr = setXML("FAIL", ""); writer.write(noticeStr); writer.flush(); System.out.println("===============退款失败=============="); } } @ApiOperation("退款订单查询") @GetMapping("/order/refund/{orderId}") public ResponseBase refundQuery(@PathVariable(value = "orderId") String orderId) { try { WxPayRefundQueryResult refundQueryResult = wxPayService.refundQuery(null, orderId, null, null); } catch (WxPayException e) { e.printStackTrace(); return responseError(500, "查询退款异常"); } return responseSuccess(new ResultVO()); } }