Day19(微信支付)

所有代码发布在 https://github.com/hades0525/leyou

订单微服务

  1. 查询订单(提交订单后展示订单)
  • OrderController
		/**
		*根据订单id查询订单
		*@param id
		*@return
		*/
		@GetMapping("{id}")
		publicResponseEntity<Order>queryOrderById(@PathVariable("id")Longid){
		returnResponseEntity.ok(orderService.queryOrderById(id));
		}
  • OrderService
		/**
		*根据订单id查询订单
		*@paramid
		*@return
		*/
		publicOrderqueryOrderById(Longid){
		//查询订单
		Orderorder=orderMapper.selectByPrimaryKey(id);
		if(order==null){
		thrownewLyException(ExceptionEnum.ORDER_NOT_FOUND);
		}
		
		//查询订单详情
		OrderDetaildetail=newOrderDetail();
		detail.setOrderId(id);
		List<OrderDetail>details=detailMapper.select(detail);
		if(CollectionUtils.isEmpty(details)){
		thrownewLyException(ExceptionEnum.ORDER_DETAIL_NOT_FOUND);
		}
		order.setOrderDetails(details);
		
		//查询订单状态
		OrderStatusorderStatus=statusMapper.selectByPrimaryKey(id);
		if(orderStatus==null){
		thrownewLyException(ExceptionEnum.ORDER_STATUS_NOT_FOUND);
		}
		order.setOrderStatus(orderStatus);
		returnorder;
		}

微信支付

  1. 微信支付需要的数据,写到配置文件中
  • applicatoin.yml
		ly:  
			pay:
		            appID: wx8397f8696b538317
		            mchID: 1472426802
		            key: T6m9iK73b0kn9g5v426MKfHQH7X8rKwb
		            httpConnectTimeoutMs: 1000
		            httpReadTimeoutMs: 8000
		            notifyUrl: http://ae4cja.natappfree.cc/notify/wxpay
  1. 加载配置到WXpay
  • PayConfig
		@Data
		publicclassPayConfigimplementsWXPayConfig{
		
		/**
		*公众账号ID
		*/
		privateStringappID;
		
		/**
		*商户号
		*/
		privateStringmchID;
		
		/**
		*生成签名的密钥
		*/
		privateStringkey;
		
		/**
		*连接超时时间
		*/
		privateinthttpConnectTimeoutMs;
		
		/**
		*读取超时时间
		*/
		privateinthttpReadTimeoutMs;
		
		/**
		*读取超时时间
		*/
		privateStringnotifyUrl;
		
		
		@Override
		publicInputStreamgetCertStream(){
		return null;
		}
		
		}
  • WXPayConfiguration
		@Configuration
		public class WXPayConfiguration{
		
		@Bean
		@ConfigurationProperties(prefix="ly.pay")
		public PayConfig payConfig(){
		return new PayConfig();
		}
		
		
		@Bean
		public WXPay wxPay(PayConfigpayConfig){
			return new WXPay(payConfig,WXPayConstants.SignType.HMACSHA256);
		}
		}
  1. 获取支付的url,生成二维码
  • OrderController
		/**
		*获取支付url
		*@paramorderId
		*@return
		*/
		@GetMapping("url/{id}")
		publicResponseEntity<String>createPayUrl(@PathVariable("id")LongorderId){
		returnResponseEntity.ok(orderService.createPayUrl(orderId));
		}
  • OrderService
		/**
		*获取支付url
		*@paramorderId
		*@return
		*/
		public String createPayUrl(Long orderId){
		//查询订单
		Order order=queryOrderById(orderId);
		//判断订单状态
		Integer status=order.getOrderStatus().getStatus();
		if(status!=OrderStatusEnum.UN_PAY.value()){
		thrownewLyException(ExceptionEnum.ORDER_STATUS_ERROR);
		}
		//支付金额
		LongactualPay=order.getActualPay();
		//商品描述
		OrderDetaildetail=order.getOrderDetails().get(0);
		Stringdesc=detail.getTitle();
		//returnpayHelper.createOrder(orderId,actualPay,desc);
		return"weixin://wxpay/bizpayurl?pr=IEukvBd";
		}
  • PayHelper.createOrder 微信创建订单
		@Autowired
		privateWXPaywxPay;
		
		@Autowired
		privatePayConfigconfig;
		
		@Autowired
		privateOrderMapperorderMapper;
		
		@Autowired
		private OrderStatusMapper statusMapper;
		public String createOrder(LongorderId,LongtotalPay,Stringdesc){
		
		try{
		Map<String,String>data=newHashMap<>();
		//商品描述
		data.put("body",desc);
		//订单号
		data.put("out_trade_no",orderId.toString());
		//金额,单位是分
		data.put("total_fee",totalPay.toString());
		//调用微信支付的终端IP(estore商城的IP)
		data.put("spbill_create_ip","127.0.0.1");
		//回调地址
		data.put("notify_url",config.getNotifyUrl());
		//交易类型为扫码支付
		data.put("trade_type","NATIVE");
		
		Map<String,String>result=this.wxPay.unifiedOrder(data);
		//判断标识
		isSuccess(result);
		
		//下单成功,获取url
		Stringurl=result.get("code_url");
		returnurl;
		}catch(Exceptione){
		log.error("[微信下单创建订单]创建预交易订单异常",e);
		returnnull;
		}
		}
  • PayHelper.isSuccess 判断是否创建成功
		/**
		*判断标识
		*@paramresult
		*/
		public void isSuccess(Map<String,String>result){
		//判断通信标识
		String returnCode=result.get("return_code");
		if(FAIL.equals(returnCode)){
		//通信失败
		log.error("[微信下单通信标识]微信下单通信失败,失败原因:{}",result.get("return_msg"));
		throw new LyException(ExceptionEnum.WX_PAY_ORDER_FALI);
		}
		
		//判断业务标识
		String resultCode=result.get("result_code");
		if(FAIL.equals(resultCode)){
		//通信失败
		log.error("[微信下单业务标识]微信下单通信失败,错误码:{},错误原因:{}",
		result.get("err_code"),result.get("err_code_des"));
		throw new LyException(ExceptionEnum.WX_PAY_ORDER_FALI);
		}
		}
  • 生成二维码 使用qrcode.min.js
		   // 生成付款链接
		                    ly.http.get("/order-service/order/url/" + id).then(resp => {
		                        new QRCode(document.getElementById("qrImage"), {
		                            text: resp.data,
		                            width: 250,
		                            height: 250,
		                            colorDark: "#000000",
		                            colorLight: "#ffffff",
		                            correctLevel: QRCode.CorrectLevel.H
		                        });
		
		                    })
  1. 支付成功并通知
  • 使用内网穿透,让外网访问本地的应用
    § 使用NATAPP生成ip
  • 微信支付结果通知的url是post请求并且参数是xml格式的
    § 要让参数是xml格式。
    § springMVC实现序列化是通过消息转化器
    § 要让消息转化器可以序列化jason或者xml需要引入相关的依赖
    § 之前已经在ly-common中已经引入了jakson的类,现在需要引入xml的类
			<dependency>
			<groupId>com.fasterxml.jackson.dataformat</groupId>
			<artifactId>jackson-dataformat-xml</artifactId>
			<version>2.9.8</version>
			</dependency>
		@RestController
		@RequestMapping("notify")
		@Slf4j
		publicclassNotifyController{
		
		@Autowired
		privateOrderServiceorderService;
		
		@PostMapping(value="wxpay",produces="application/xml")
		publicMap<String,String>hello(@RequestBodyMap<String,String>result){
		//处理回调
		orderService.handleNotify(result);
		
		log.info("[支付回调]接受微信支付回调,结果{}",result);
		//返回成功
		Map<String,String>msg=newHashMap<>();
		msg.put("return_code","SUCCESS");
		msg.put("return_msg","OK");
		
		return msg;
		}
		}
  • OrderService.handleNotify 处理回调参数
		/**
		*支付结果通知
		*@paramresult
		*/
		publicvoidhandleNotify(Map<String,String>result){
		//1数据校验
		payHelper.isSuccess(result);
		
		//2校验签名
		payHelper.isValidSign(result);
		
		//3校验金额
		StringtotalFeeStr=result.get("total_fee");
		//订单号
		StringtradeNo=result.get("out_trade_no");
		if(StringUtils.isBlank(totalFeeStr)||StringUtils.isBlank(tradeNo)){
		thrownewLyException(ExceptionEnum.INVALID_ORDER_PARAM);
		}
		//3.1获取结果中的金额
		longtotalFee=Long.valueOf(totalFeeStr);
		//获取订单号
		LongorderId=Long.valueOf(tradeNo);
		
		//4查询订单
		Orderorder=orderMapper.selectByPrimaryKey(orderId);
		if(totalFee!=order.getActualPay()){
		//金额不符
		thrownewLyException(ExceptionEnum.INVALID_ORDER_PARAM);
		}
		
		//5修改订单状态
		OrderStatusstatus=newOrderStatus();
		status.setStatus(OrderStatusEnum.PAYED.value());
		status.setOrderId(orderId);
		status.setPaymentTime(newDate());
		intcount=statusMapper.updateByPrimaryKeySelective(status);
		if(count!=1){
		thrownewLyException(ExceptionEnum.UPDATE_ORDERSTATUS_ERROR);
		}
		
		log.info("[订单回调]订单支付成功!订单编号:{}",orderId);
		}
  • payhelper.isValidSign 校验签名
		/**
		*校验签名
		*@paramdata
		*/
		publicvoidisValidSign(Map<String,String>data){
		//重新生成签名
		try{
		Stringsign1=WXPayUtil.generateSignature(data,this.config.getKey(),WXPayConstants.SignType.HMACSHA256);
		Stringsign2=WXPayUtil.generateSignature(data,this.config.getKey(),WXPayConstants.SignType.MD5);
		
		//和传过来的签名进行比较
		
		Stringsign=data.get("sign");
		if(!StringUtils.equals(sign,sign1)&&!StringUtils.equals(sign,sign2)){
		//签名有误
		thrownewLyException(ExceptionEnum.INVALID_SIGN_ERROR);
		}
		}catch(Exceptione){
		thrownewLyException(ExceptionEnum.INVALID_SIGN_ERROR);
		
		}
		}
  1. 前端查询订单状态,跳转页面
  • 前端 定时器,隔一段时间查一次支付状态
		//开启定时任务,查询付款状态
		consttaskId=setInterval(()=>{
		ly.http.get("/order-service/order/state/"+id)
		.then(resp=>{
		leti=resp.data;
		if(i===1){
		//付款成功
		clearInterval(taskId);
		//跳转到付款成功页
		location.href="/paysuccess.html?orderId="+id;
		}elseif(i===2){
		//付款失败
		clearInterval(taskId);
		//跳转到付款失败页
		location.href="/payfail.html";
		}
		}).catch((e)=>{
		alert("支付状态查询失败,请刷新页面重试。");
		clearInterval(taskId);
		})
		},3000);
  • 定义一个枚举PayState,表示支付状态
		public enum PayState{
		/**
		*未支付0
		*支付成功1
		*支付失败2
		*/
		NOT_PAY(0),SUCCESS(1),FAIL(2);
		
		PayState(intvalue){
		this.value=value;
		}
		
		int value;
		
		public int getValue(){
		return value;
		}
		}
  • OrderController
		/**
		*查询订单状态
		*@paramorderId
		*@return
		*/
		@GetMapping("state/{id}")
		public ResponseEntity<Integer> queryOrderStatus(@PathVariable("id")Long orderId){
		returnResponseEntity.ok(orderService.queryOrderStatus(orderId).getValue());
		}
		• OrderService
		/**
		*查询订单状态
		*@paramorderId
		*@return
		*/
		publicPayStatequeryOrderStatus(LongorderId){
		//查询订单状态
		OrderStatusorderStatus=statusMapper.selectByPrimaryKey(orderId);
		Integerstatus=orderStatus.getStatus();
		//判断是否支付
		if(status!=OrderStatusEnum.UN_PAY.value()){
		//如果已支付,就是真的支付了
		returnPayState.SUCCESS;
		}
		
		//如果未支付,需要到微信查询支付状态
		returnpayHelper.queryPayState(orderId);
		}
  • PayHelper.queryPayState 可能已支付,但回调函数还未执行所以要到微信查一下支付的状态。
		/**
		*查询订单状态
		*@paramorderId
		*@return
		*/
		publicPayStatequeryPayState(Long orderId){
		try{
		Map<String,String>data=newHashMap<>();
		//订单号
		data.put("out_trade_no",orderId.toString());
		//查询状态
		Map<String,String>result=wxPay.orderQuery(data);
		if(result==null){
		//未查询到结果,认为是未付款
		returnPayState.NOT_PAY;
		}
		//校验状态
		isSuccess(result);
		
		//校验签名
		isValidSign(result);
		
		//3校验金额
		StringtotalFeeStr=result.get("total_fee");
		//订单号
		StringtradeNo=result.get("out_trade_no");
		if(StringUtils.isBlank(totalFeeStr)||StringUtils.isBlank(tradeNo)){
		thrownewLyException(ExceptionEnum.INVALID_ORDER_PARAM);
		}
		//3.1获取结果中的金额
		longtotalFee=Long.valueOf(totalFeeStr);
		//获取订单号
		
		//4查询订单
		Orderorder=orderMapper.selectByPrimaryKey(orderId);
		if(totalFee!=order.getActualPay()){
		//金额不符
		thrownewLyException(ExceptionEnum.INVALID_ORDER_PARAM);
		}
		Stringstate=result.get("trade_state");
		if(SUCCESS.equals(state)){
		//5修改订单状态
		OrderStatusstatus=newOrderStatus();
		status.setStatus(OrderStatusEnum.PAYED.value());
		status.setOrderId(orderId);
		status.setPaymentTime(newDate());
		intcount=statusMapper.updateByPrimaryKeySelective(status);
		if(count!=1){
		thrownewLyException(ExceptionEnum.UPDATE_ORDERSTATUS_ERROR);
		}
		returnPayState.SUCCESS;
		}
		
		if("NOTPAY".equals(state)||"USERPAYING".equals(state)){
		return PayState.NOT_PAY;
		}
		
		returnPayState.FAIL;
		
		}catch(Exceptione){
		log.error("查询订单状态异常",e);
		returnPayState.NOT_PAY;
		}
		}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值