|
@@ -0,0 +1,325 @@
|
|
|
|
|
+package com.izouma.weixin.web;
|
|
|
|
|
+
|
|
|
|
|
+import cfca.org.bouncycastle.util.encoders.Base64;
|
|
|
|
|
+import cfca.x509.certificate.X509Cert;
|
|
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
|
|
+import com.izouma.agpay.bean.ApiHead;
|
|
|
|
|
+import com.izouma.agpay.bean.ApiMessage;
|
|
|
|
|
+import com.izouma.agpay.bean.QR1008ReqBody;
|
|
|
|
|
+import com.izouma.agpay.util.HttpClient431Util;
|
|
|
|
|
+import com.izouma.agpay.util.MessageUtil;
|
|
|
|
|
+import com.izouma.agpay.util.RsaP1Util;
|
|
|
|
|
+import com.izouma.awesomeadmin.constant.AppConstant;
|
|
|
|
|
+import com.izouma.awesomeadmin.service.UserOrderService;
|
|
|
|
|
+import com.izouma.awesomeadmin.util.PropertiesFileLoader;
|
|
|
|
|
+import com.izouma.weixin.dao.WxpayTempMapper;
|
|
|
|
|
+import com.izouma.weixin.model.WxpayTemp;
|
|
|
|
|
+import com.izouma.weixin.util.WeixinUtil;
|
|
|
|
|
+import org.apache.commons.lang.StringUtils;
|
|
|
|
|
+import org.apache.log4j.Logger;
|
|
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
+import org.springframework.stereotype.Controller;
|
|
|
|
|
+import org.springframework.web.bind.annotation.RequestMapping;
|
|
|
|
|
+import org.springframework.web.bind.annotation.RequestMethod;
|
|
|
|
|
+import org.springframework.web.bind.annotation.RequestParam;
|
|
|
|
|
+import org.springframework.web.bind.annotation.ResponseBody;
|
|
|
|
|
+import org.springframework.web.context.request.RequestContextHolder;
|
|
|
|
|
+import org.springframework.web.context.request.ServletRequestAttributes;
|
|
|
|
|
+import org.springframework.web.servlet.ModelAndView;
|
|
|
|
|
+
|
|
|
|
|
+import javax.servlet.http.HttpServletRequest;
|
|
|
|
|
+import javax.servlet.http.HttpServletResponse;
|
|
|
|
|
+import javax.servlet.http.HttpSession;
|
|
|
|
|
+import java.io.BufferedOutputStream;
|
|
|
|
|
+import java.io.FileInputStream;
|
|
|
|
|
+import java.io.IOException;
|
|
|
|
|
+import java.math.BigDecimal;
|
|
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
|
|
+import java.util.Date;
|
|
|
|
|
+import java.util.HashMap;
|
|
|
|
|
+import java.util.Map;
|
|
|
|
|
+
|
|
|
|
|
+@Controller
|
|
|
|
|
+@RequestMapping("/agpay")
|
|
|
|
|
+public class AGController {
|
|
|
|
|
+
|
|
|
|
|
+ private static Logger logger = Logger.getLogger(AGController.class);
|
|
|
|
|
+
|
|
|
|
|
+ String url = PropertiesFileLoader.getProperties("agpay_api_url");
|
|
|
|
|
+ String merchantPfxPath = PropertiesFileLoader.getProperties("agpay_merchantPfxPath");
|
|
|
|
|
+ String publicKeyPath = PropertiesFileLoader.getProperties("agpay_publicKeyPath");
|
|
|
|
|
+ String agpay_platmerid = PropertiesFileLoader.getProperties("agpay_platmerid");
|
|
|
|
|
+ String agpay_pwd = PropertiesFileLoader.getProperties("agpay_pwd");
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private UserOrderService userOrderService;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private WxpayTempMapper wxpayTempMapper;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ @RequestMapping(value = "/notify", method = RequestMethod.POST)
|
|
|
|
|
+ @ResponseBody
|
|
|
|
|
+ public ModelAndView notify(HttpServletRequest request, HttpServletResponse response) {
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ ApiMessage m = notifyMap(request, response);
|
|
|
|
|
+ if (m != null && "C000000000".equals(m.getMessage().getData().getHead().getRespcode())) {
|
|
|
|
|
+
|
|
|
|
|
+ JSONObject bodyJson = JSON.parseObject(JSON.toJSONString(m.getMessage().getData().getBody()));
|
|
|
|
|
+
|
|
|
|
|
+ String tranflow = m.getMessage().getData().getHead().getTranflow();
|
|
|
|
|
+ String payamount = bodyJson.getString("payamount");
|
|
|
|
|
+
|
|
|
|
|
+ if (Double.valueOf(payamount) > 0) {
|
|
|
|
|
+
|
|
|
|
|
+ WxpayTemp wxpayTemp = new WxpayTemp();
|
|
|
|
|
+ wxpayTemp.setTransactionId(tranflow);
|
|
|
|
|
+ wxpayTemp = wxpayTempMapper.queryWxpayTemp(wxpayTemp);
|
|
|
|
|
+ if (wxpayTemp != null) {
|
|
|
|
|
+
|
|
|
|
|
+ userOrderService.payOrder(wxpayTemp.getOrderId(), wxpayTemp.getCoin().doubleValue(),
|
|
|
|
|
+ wxpayTemp.getPoint().doubleValue(), wxpayTemp.getCash().doubleValue(), AppConstant.PayMode.AG_PAY);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ logger.error("agpay支付回调异常", e);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ @RequestMapping(value = "/unifiedOrder", method = RequestMethod.GET)
|
|
|
|
|
+ @ResponseBody
|
|
|
|
|
+ public Map<String, String> unifiedOrder(@RequestParam(required = true, value = "orderId") String orderId, @RequestParam(required = true, value = "coin") double coin,
|
|
|
|
|
+ @RequestParam(required = true, value = "point") double point) {
|
|
|
|
|
+ Map<String, String> resultMap = new HashMap<>();
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ RsaP1Util rsaP1Util = new RsaP1Util();
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+
|
|
|
|
|
+ HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
|
|
|
|
+
|
|
|
|
|
+ String ip = WeixinUtil.getIpAdderss(request);
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ double cash = userOrderService.calculatedPrice(orderId, coin, point);
|
|
|
|
|
+ double total = 0;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ total = cash;
|
|
|
|
|
+
|
|
|
|
|
+ //测试为一分
|
|
|
|
|
+ total = 0.01;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ //按照要求组装好报文
|
|
|
|
|
+ ApiHead head = new ApiHead();
|
|
|
|
|
+ QR1008ReqBody body = new QR1008ReqBody();
|
|
|
|
|
+
|
|
|
|
|
+ final SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
|
|
|
|
|
+ final String timeStr = formatter.format(new Date());
|
|
|
|
|
+
|
|
|
|
|
+ head.setClienttime(timeStr);
|
|
|
|
|
+ head.setPlatmerid(agpay_platmerid);
|
|
|
|
|
+ head.setTrancode("QR1008");
|
|
|
|
|
+ head.setTranflow(agpay_platmerid + timeStr + WeixinUtil.getRandomNum(6));
|
|
|
|
|
+
|
|
|
|
|
+ body.setPayamount("0.01");
|
|
|
|
|
+ body.setAmount(String.valueOf(cash));
|
|
|
|
|
+ body.setAgentid("API_WXAPP");
|
|
|
|
|
+ body.setCommodityname("一米世界-导游包");
|
|
|
|
|
+ body.setNotifyurl(PropertiesFileLoader.getProperties("agpay_notify_url"));
|
|
|
|
|
+ body.setSpbillcreateip(ip);
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ //head和body组装对应的报文
|
|
|
|
|
+ ApiMessage father = new ApiMessage();
|
|
|
|
|
+ ApiMessage.Message message = father.new Message();
|
|
|
|
|
+ ApiMessage.Message.Data data = message.new Data();
|
|
|
|
|
+ data.setHead(head);
|
|
|
|
|
+ data.setBody(body);
|
|
|
|
|
+ message.setData(data);
|
|
|
|
|
+
|
|
|
|
|
+ String bodyStr = JSON.toJSONString(data.getBody());
|
|
|
|
|
+ //生成对应的待签名串 只签名报文体
|
|
|
|
|
+ String signMessage = MessageUtil.getSignStr(bodyStr);
|
|
|
|
|
+ //生成签名
|
|
|
|
|
+ String sign = rsaP1Util.rsaP1Sign(signMessage, merchantPfxPath, "umbpay");
|
|
|
|
|
+ //得到sign后继续组装对应报文,然后加密
|
|
|
|
|
+ message.setSign(sign);
|
|
|
|
|
+ father.setMessage(message);
|
|
|
|
|
+ String messageStr = JSON.toJSONString(father);
|
|
|
|
|
+ String reqMsg = new String(rsaP1Util.envelopMessage(messageStr, publicKeyPath));
|
|
|
|
|
+ Map<String, String> params = new HashMap<String, String>();
|
|
|
|
|
+ params.put("data", reqMsg);
|
|
|
|
|
+ params.put("formatType", "json");
|
|
|
|
|
+ params.put("cryptType", "cert");
|
|
|
|
|
+ params.put("signType", "cert");
|
|
|
|
|
+ //发送请求得到结果
|
|
|
|
|
+ String result = HttpClient431Util.doPost(params, url, "UTF-8", "UTF-8");
|
|
|
|
|
+ //解密得到明文
|
|
|
|
|
+ String platinMsg = new String(rsaP1Util.openMessage(result, merchantPfxPath, "umbpay"));
|
|
|
|
|
+ System.out.println(platinMsg);
|
|
|
|
|
+ //在返回报文明文 platinMsg中获取系统返回的签名
|
|
|
|
|
+ //在返回报文明文 platinMsg中自己重新组装待签名串
|
|
|
|
|
+
|
|
|
|
|
+ ApiMessage resfather = JSON.parseObject(platinMsg, ApiMessage.class);
|
|
|
|
|
+ System.out.println(resfather);
|
|
|
|
|
+ //准备验签
|
|
|
|
|
+ FileInputStream is = new FileInputStream(publicKeyPath);
|
|
|
|
|
+ X509Cert x509Cert = new X509Cert(is);
|
|
|
|
|
+ String cert = new String(Base64.encode(x509Cert.getEncoded()), "UTF-8");
|
|
|
|
|
+ //验签
|
|
|
|
|
+ String signdata = MessageUtil.getSignStr(JSON.toJSONString(resfather.getMessage().getData().getBody()));
|
|
|
|
|
+
|
|
|
|
|
+ if (rsaP1Util.rsaP1Verify(resfather.getMessage().getSign(), signdata, cert.getBytes("UTF-8"))) {
|
|
|
|
|
+
|
|
|
|
|
+ //验签成功,业务处理
|
|
|
|
|
+ WxpayTemp wxpayTemp = new WxpayTemp();
|
|
|
|
|
+ wxpayTemp.setOrderId(orderId);
|
|
|
|
|
+ wxpayTemp.setCoin(BigDecimal.valueOf(coin));
|
|
|
|
|
+ wxpayTemp.setPoint(BigDecimal.valueOf(point));
|
|
|
|
|
+ wxpayTemp.setCash(BigDecimal.valueOf(cash));
|
|
|
|
|
+ wxpayTemp.setTotalAmount(BigDecimal.valueOf(total));
|
|
|
|
|
+ wxpayTemp.setTransactionId(head.getTranflow());
|
|
|
|
|
+ wxpayTemp.setOutTradeNo("agpay_order");
|
|
|
|
|
+ wxpayTemp.setTypeFlag(AppConstant.Aliapi.BUY);
|
|
|
|
|
+
|
|
|
|
|
+ wxpayTempMapper.insertSelective(wxpayTemp);
|
|
|
|
|
+ JSONObject bodyJson = JSON.parseObject((JSON.toJSONString(resfather.getMessage().getData().getBody())));
|
|
|
|
|
+
|
|
|
|
|
+ JSONObject payinfo = JSON.parseObject((bodyJson.getString("payinfo")));
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ resultMap.put("appId", StringUtils.isNotEmpty(payinfo.getString("appId"))?payinfo.getString("appId"):PropertiesFileLoader.getProperties("agpay_wx_appid"));
|
|
|
|
|
+ resultMap.put("partnerid", payinfo.getString("partnerId"));
|
|
|
|
|
+ resultMap.put("prepayid", payinfo.getString("prepayId"));
|
|
|
|
|
+ resultMap.put("timestamp", payinfo.getString("timeStamp"));
|
|
|
|
|
+ resultMap.put("noncestr", payinfo.getString("nonceStr"));
|
|
|
|
|
+ resultMap.put("package", "Sign=WXPay");
|
|
|
|
|
+ resultMap.put("sign", payinfo.getString("sign"));
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+ //验签失败,数据可能被篡改
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ //result.put("code_url", unified.get("code_url"));
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ logger.error("", e);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ return resultMap;
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 解析微信支付回调结果
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param request
|
|
|
|
|
+ * @param response
|
|
|
|
|
+ * @return
|
|
|
|
|
+ */
|
|
|
|
|
+ public ApiMessage notifyMap(HttpServletRequest request, HttpServletResponse response) {
|
|
|
|
|
+
|
|
|
|
|
+ RsaP1Util rsaP1Util = new RsaP1Util();
|
|
|
|
|
+
|
|
|
|
|
+ logger.info("payOrder:支付订单");
|
|
|
|
|
+ ApiMessage notifyMap = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+
|
|
|
|
|
+ System.out.print("agpay支付回调数据开始");
|
|
|
|
|
+ String inputLine;
|
|
|
|
|
+ String notityXml = "";
|
|
|
|
|
+ String resXml = "";
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ while ((inputLine = request.getReader().readLine()) != null) {
|
|
|
|
|
+ notityXml += inputLine;
|
|
|
|
|
+ }
|
|
|
|
|
+ request.getReader().close();
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ e.printStackTrace();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ System.out.println("接收到的报文:" + notityXml);
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ //解密得到明文
|
|
|
|
|
+ String platinMsg = new String(rsaP1Util.openMessage(notityXml, merchantPfxPath, "umbpay"));
|
|
|
|
|
+ System.out.println(platinMsg);
|
|
|
|
|
+ //在返回报文明文 platinMsg中获取系统返回的签名
|
|
|
|
|
+ //在返回报文明文 platinMsg中自己重新组装待签名串
|
|
|
|
|
+
|
|
|
|
|
+ ApiMessage resfather = JSON.parseObject(platinMsg, ApiMessage.class);
|
|
|
|
|
+ System.out.println(resfather);
|
|
|
|
|
+ //准备验签
|
|
|
|
|
+ FileInputStream is = new FileInputStream(publicKeyPath);
|
|
|
|
|
+ X509Cert x509Cert = new X509Cert(is);
|
|
|
|
|
+ String cert = new String(Base64.encode(x509Cert.getEncoded()), "UTF-8");
|
|
|
|
|
+ //验签
|
|
|
|
|
+ String signdata = MessageUtil.getSignStr(JSON.toJSONString(resfather.getMessage().getData().getBody()));
|
|
|
|
|
+
|
|
|
|
|
+ if (rsaP1Util.rsaP1Verify(resfather.getMessage().getSign(), signdata, cert.getBytes("UTF-8"))) {
|
|
|
|
|
+
|
|
|
|
|
+ //验签成功,业务处理
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ notifyMap = resfather;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // 进行处理。
|
|
|
|
|
+ // 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户侧订单状态从退款改成支付成功
|
|
|
|
|
+ if ("C000000000".equals(notifyMap.getMessage().getData().getHead().getRespcode())) {
|
|
|
|
|
+ //支付成功
|
|
|
|
|
+ resXml = "SUCC";
|
|
|
|
|
+ } else {
|
|
|
|
|
+ resXml = "FAIL";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+ resXml = "FAIL";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ System.out.println("agpay支付回调数据结束");
|
|
|
|
|
+
|
|
|
|
|
+ HttpSession session = request.getSession();
|
|
|
|
|
+ session.setAttribute("notify", "agpay支付回调");
|
|
|
|
|
+ try {
|
|
|
|
|
+ BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
|
|
|
|
|
+ out.write(resXml.getBytes());
|
|
|
|
|
+ out.flush();
|
|
|
|
|
+ out.close();
|
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
|
+ // TODO Auto-generated catch block
|
|
|
|
|
+ e.printStackTrace();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ logger.error("payOrder:支付订单异常", e);
|
|
|
|
|
+ }
|
|
|
|
|
+ return notifyMap;
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+}
|