品優購項目筆記(十四):微信支付

訂單

訂單三張表關係

在這裏插入圖片描述

提交訂單

controller

@RestController
@RequestMapping("/order")
public class OrderController {
    @Reference
    private OrderService orderService;

    @RequestMapping("/add")
    public Result add(@RequestBody Order order) {
        try {
            String userName = SecurityContextHolder.getContext().getAuthentication().getName();
            order.setUserId(userName);

            orderService.add(order);
            return new Result(true, "保存成功!");
        } catch (Exception e) {
            e.printStackTrace();
            return new Result(false, "保存失敗!");
        }
    }
}

Service

@Service
@Transactional
public class OrderServiceImpl implements OrderService {
    @Autowired
    private PayLogDao payLogDao;

    @Autowired
    private OrderDao orderDao;

    @Autowired
    private OrderItemDao orderItemDao;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private IdWorker idWorker;

    @Override
    public void add(Order order) {
        //1. 從訂單對象中獲取當前登錄用戶用戶名
        String userId = order.getUserId();
        //2. 根據用戶名獲取購物車集合
        List<BuyerCart> cartList = (List<BuyerCart>) redisTemplate.boundHashOps(Constants.CART_LIST_REDIS).get(userId);
        List<String> orderIdList = new ArrayList();//訂單ID列表
        double total_money = 0;//總金額 (元)

        //3. 遍歷購物車集合
        if (cartList != null) {
            for (BuyerCart cart : cartList) {
                //TODO 4. 根據購物車對象保存訂單數據
                long orderId = idWorker.nextId();
                System.out.println("sellerId:" + cart.getSellerId());
                Order tborder = new Order();//新創建訂單對象
                tborder.setOrderId(orderId);//訂單ID
                tborder.setUserId(order.getUserId());//用戶名
                tborder.setPaymentType(order.getPaymentType());//支付類型
                tborder.setStatus("1");//狀態:未付款
                tborder.setCreateTime(new Date());//訂單創建日期
                tborder.setUpdateTime(new Date());//訂單更新日期
                tborder.setReceiverAreaName(order.getReceiverAreaName());//地址
                tborder.setReceiverMobile(order.getReceiverMobile());//手機號
                tborder.setReceiver(order.getReceiver());//收貨人
                tborder.setSourceType(order.getSourceType());//訂單來源
                tborder.setSellerId(cart.getSellerId());//商家ID
                //循環購物車明細
                double money = 0;

                //5. 從購物車中獲取購物項集合
                List<OrderItem> orderItemList = cart.getOrderItemList();
                //6. 遍歷購物項集合
                if (orderItemList != null) {
                    for (OrderItem orderItem : orderItemList) {
                        //TODO 7. 根據購物項對象保存訂單詳情數據
                        orderItem.setId(idWorker.nextId());
                        orderItem.setOrderId(orderId);//訂單ID
                        orderItem.setSellerId(cart.getSellerId());
                        money += orderItem.getTotalFee().doubleValue();//金額累加
                        orderItemDao.insertSelective(orderItem);

                    }
                }
                tborder.setPayment(new BigDecimal(money));
                orderDao.insertSelective(tborder);
                orderIdList.add(orderId + "");//添加到訂單列表
                total_money += money;//累加到總金額

            }
        }
        //TODO 8. 計算總價錢保存支付日誌數據
        if ("1".equals(order.getPaymentType())) {//如果是微信支付
            PayLog payLog = new PayLog();
            String outTradeNo = idWorker.nextId() + "";//支付訂單號
            payLog.setOutTradeNo(outTradeNo);//支付訂單號
            payLog.setCreateTime(new Date());//創建時間
            //訂單號列表,逗號分隔
            String ids = orderIdList.toString().replace("[", "").replace("]", "").replace(" ", "");
            payLog.setOrderList(ids);//訂單號列表,逗號分隔
            payLog.setPayType("1");//支付類型
            payLog.setTotalFee((long) (total_money * 100));//總金額(分)
            payLog.setTradeState("0");//支付狀態
            payLog.setUserId(order.getUserId());//用戶ID
            payLogDao.insertSelective(payLog);//插入到支付日誌表
            //TODO 9. 使用當前登錄用戶的用戶名作爲key, 支付日誌對象作爲value存入redis中供支付使用
            redisTemplate.boundHashOps("payLog").put(order.getUserId(), payLog);//放入緩存
        }
        //TODO 10. 根據當前登錄用戶的用戶名刪除購物車
        redisTemplate.boundHashOps(Constants.CART_LIST_REDIS).delete(order.getUserId());
    }
}

二維碼

介紹

二維碼又稱QR Code,QR全稱Quick Response,是一個近幾年來移動設備上超流行的一種編碼方式,它比傳統的Bar Code條形碼能存更多的信息,也能表示更多的數據類型。
二維條碼/二維碼(2-dimensional bar code)是用某種特定的幾何圖形按一定規律在平面(二維方向上)分佈的黑白相間的圖形記錄數據符號信息的;在代碼編制上巧妙地利用構成計算機內部邏輯基礎的“0”、“1”比特流的概念,使用若干個與二進制相對應的幾何形體來表示文字數值信息,通過圖象輸入設備或光電掃描設備自動識讀以實現信息自動處理:它具有條碼技術的一些共性:每種碼制有其特定的字符集;每個字符佔有一定的寬度;具有一定的校驗功能等。同時還具有對不同行的信息自動識別功能、及處理圖形旋轉變化點。

優勢

 信息容量大, 可以容納多達1850個大寫字母或2710個數字或500多個漢字
 應用範圍廣, 支持文字,聲音,圖片,指紋等等…
 容錯能力強, 即使圖片出現部分破損也能使用
 成本低, 容易製作

容錯級別

容錯級別也就是容錯率, 相當於部分二維碼被遮擋仍然可以被掃描出來.
L級(低) 7%的碼字可以被恢復。
M級(中) 的碼字的15%可以被恢復。
Q級(四分)的碼字的25%可以被恢復。
H級(高) 的碼字的30%可以被恢復。

qrious二維碼生成插件

這是前端的二維碼生成工具

<html>
<head>
<title>二維碼入門小demo</title>
</head>
<body>
<img id="qrious">
<script src="qrious.min.js"></script>
<script>
 var qr = new QRious({
	   element:document.getElementById('qrious'),
	   size:250, 	   level:'H',	   value:'https://www.baidu.com'
	});
</script>
</body>
</html>

在這裏插入圖片描述

微信支付

微信支付流程

紅色部分爲項目需要實現的部分
在這裏插入圖片描述

項目支付流程

在這裏插入圖片描述

生成支付鏈接

controller

/**
 * 支付業務
 */
@RestController
@RequestMapping("/pay")
public class PayController {

    @Reference
    private OrderService orderService;
    @Reference
    private PayService payService;
    /**
     * 根據支付單號和總金額調用微信統一下單接口,生成支付鏈接返回
     * @return
     */
    @RequestMapping("/createNative")
    public Map createNative(){
        //1.獲取用戶名
        String username = SecurityContextHolder.getContext().getAuthentication().getName();
        //2.獲取支付日誌對象
        PayLog payLog = orderService.getPayLogByUsername(username);
        if (payLog!=null){
            //3.調用統一下單接口,生成支付鏈接
            Map map = payService.createNative(payLog.getOutTradeNo(), "1");//payLog.getTotalFee()
            return map;
        }
        return new HashMap();
    }
}

service:注意需要發送https請求,所以要用到HttpClient工具類

@Service
public class PayServiceImpl implements PayService {
    //公衆號唯一標識
    @Value("${appid}")
    private String appid;
    //財付通平臺商戶賬號
    @Value("${partner}")
    private String partner;
    //密鑰
    @Value("${partnerkey}")
    private String partnerkey;
    //回調地址
    @Value("${notifyurl}")
    private String notifyurl;

    @Override
    public Map createNative(String outTradeNo, String totalFee) {
        //1.創建參數
        Map<String,String> param=new HashMap();//創建參數
        param.put("appid", appid);//公衆號
        param.put("mch_id", partner);//商戶號
        param.put("nonce_str", WXPayUtil.generateNonceStr());//隨機字符串
        param.put("body", "品優購");//商品描述
        param.put("out_trade_no", outTradeNo);//商戶訂單號
        param.put("total_fee",totalFee);//總金額(分)
        param.put("spbill_create_ip", "127.0.0.1");//IP
        param.put("notify_url", "http://www.itcast.cn");//回調地址(隨便寫)
        param.put("trade_type", "NATIVE");//交易類型
        try {
            //2.生成要發送的xml
            String xmlParam = WXPayUtil.generateSignedXml(param, partnerkey);
            System.out.println(xmlParam);
            HttpClient client=new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
            client.setHttps(true);
            client.setXmlParam(xmlParam);
            client.post();
            //3.獲得結果
            String result = client.getContent();
            System.out.println(result);
            Map<String, String> resultMap = WXPayUtil.xmlToMap(result);
            Map<String, String> map=new HashMap<>();
            map.put("code_url", resultMap.get("code_url"));//支付地址
            map.put("total_fee", totalFee);//總金額
            map.put("out_trade_no",outTradeNo);//訂單號
            return map;
        } catch (Exception e) {
            e.printStackTrace();
            return new HashMap<>();
        }
    }
}

HttpClient

/**
 * http請求客戶端
 * 
 * @author Administrator
 * 
 */
public class HttpClient {
	private String url;
	private Map<String, String> param;
	private int statusCode;
	private String content;
	private String xmlParam;
	private boolean isHttps;

	public boolean isHttps() {
		return isHttps;
	}

	public void setHttps(boolean isHttps) {
		this.isHttps = isHttps;
	}

	public String getXmlParam() {
		return xmlParam;
	}

	public void setXmlParam(String xmlParam) {
		this.xmlParam = xmlParam;
	}

	public HttpClient(String url, Map<String, String> param) {
		this.url = url;
		this.param = param;
	}

	public HttpClient(String url) {
		this.url = url;
	}

	public void setParameter(Map<String, String> map) {
		param = map;
	}

	public void addParameter(String key, String value) {
		if (param == null)
			param = new HashMap<String, String>();
		param.put(key, value);
	}

	public void post() throws ClientProtocolException, IOException {
		HttpPost http = new HttpPost(url);
		setEntity(http);
		execute(http);
	}

	public void put() throws ClientProtocolException, IOException {
		HttpPut http = new HttpPut(url);
		setEntity(http);
		execute(http);
	}

	public void get() throws ClientProtocolException, IOException {
		if (param != null) {
			StringBuilder url = new StringBuilder(this.url);
			boolean isFirst = true;
			for (String key : param.keySet()) {
				if (isFirst)
					url.append("?");
				else
					url.append("&");
				url.append(key).append("=").append(param.get(key));
			}
			this.url = url.toString();
		}
		HttpGet http = new HttpGet(url);
		execute(http);
	}

	/**
	 * set http post,put param
	 */
	private void setEntity(HttpEntityEnclosingRequestBase http) {
		if (param != null) {
			List<NameValuePair> nvps = new LinkedList<NameValuePair>();
			for (String key : param.keySet())
				nvps.add(new BasicNameValuePair(key, param.get(key))); // 參數
			http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // 設置參數
		}
		if (xmlParam != null) {
			http.setEntity(new StringEntity(xmlParam, Consts.UTF_8));
		}
	}

	private void execute(HttpUriRequest http) throws ClientProtocolException,
			IOException {
		CloseableHttpClient httpClient = null;
		try {
			if (isHttps) {
				SSLContext sslContext = new SSLContextBuilder()
						.loadTrustMaterial(null, new TrustStrategy() {
							// 信任所有
							public boolean isTrusted(X509Certificate[] chain,
									String authType)
									throws CertificateException {
								return true;
							}
						}).build();
				SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
						sslContext);
				httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
						.build();
			} else {
				httpClient = HttpClients.createDefault();
			}
			CloseableHttpResponse response = httpClient.execute(http);
			try {
				if (response != null) {
					if (response.getStatusLine() != null)
						statusCode = response.getStatusLine().getStatusCode();
					HttpEntity entity = response.getEntity();
					// 響應內容
					content = EntityUtils.toString(entity, Consts.UTF_8);
				}
			} finally {
				response.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			httpClient.close();
		}
	}

	public int getStatusCode() {
		return statusCode;
	}

	public String getContent() throws ParseException, IOException {
		return content;
	}

}

查詢是否支付成功

controller

/**
     * 調用查詢訂單接口,查詢是否支付成功
     * @param out_trade_no
     * @return
     */
    @RequestMapping("/queryPayStatus")
    public Result queryPayStatus(String out_trade_no){
        String username = SecurityContextHolder.getContext().getAuthentication().getName();
        Result result = null;
        int flag = 1;
        while (true){
            //1.判斷支付單號爲空
            if (out_trade_no == null){
                result = new Result(false,"二維碼超時");
                break;
            }
            //2.調用查詢接口
            Map map = payService.queryPayStatus(out_trade_no);
            if ("SUCCESS".equals(map.get("trade_state"))){
                result = new Result(true,"支付成功");
                //3.如果支付成功,支付日誌表和訂單表的支付狀態改爲已支付,redis的支付日誌對象刪除
                orderService.updatePayStatus(username);
                break;
            }

            try {
                Thread.sleep(3000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            //如果5分鐘沒有支付,則支付超時
            if (flag > 100){
                result = new Result(false,"二維碼超時");
                break;
            }
            flag++;
        }
        return result;
    }

service

@Override
    public Map queryPayStatus(String out_trade_no) {
        Map param=new HashMap();
        param.put("appid", appid);//公衆賬號ID
        param.put("mch_id", partner);//商戶號
        param.put("out_trade_no", out_trade_no);//訂單號
        param.put("nonce_str", WXPayUtil.generateNonceStr());//隨機字符串
        String url="https://api.mch.weixin.qq.com/pay/orderquery";
        try {
            String xmlParam = WXPayUtil.generateSignedXml(param, partnerkey);
            HttpClient client=new HttpClient(url);
            client.setHttps(true);
            client.setXmlParam(xmlParam);
            client.post();
            String result = client.getContent();
            Map<String, String> map = WXPayUtil.xmlToMap(result);
            System.out.println(map);
            return map;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章