品优购项目笔记(十四):微信支付

订单

订单三张表关系

在这里插入图片描述

提交订单

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;
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章