实现订单的生成到扫码进行支付

1. 思路 :

  1. 点击立即购买在数据库中进行添加订单,查找订单所需要的信息
  2. 点击支付 出现微信二维码进行扫描支付
  3. 返回初始界面

2. 后端接口

    //生成订单的方法
    @PostMapping("/createOrder/{courseId}")
    public R saveOrder(@PathVariable String courseId, HttpServletRequest request){
        String orderNo=orderService.createOrders(courseId, JwtUtils.getMemberIdByJwtToken(request));
        return R.ok().data("orderId",orderNo);
    }
    
   //根据订单id查询订单信息
    @GetMapping("getOrderInfo/{id}")
    public R getOrderInfo(@PathVariable String id){
        QueryWrapper<Order> wrapper = new QueryWrapper<>();
        wrapper.eq("order_no",id);
        Order order = orderService.getOne(wrapper);
        return R.ok().data("item",order);
    }

生成订单的实现类

 @Override
    public String createOrders(String courseId, String memberId) {
        //通过远程调用根据用户的id获取用户的具体信息
        UcenterMemberOrder userInfoOrder = ucenterClient.getUserInfoOrder(memberId);
        //通过远程调用根据课程id获取课程的信息
        CourseWebVoOrder courseInfoOrder = eduClient.getFrontCourseInfo(courseId);
        Order order = new Order();
        order.setOrderNo(OrderNoUtil.getOrderNo());//订单号
        order.setCourseId(courseId); //课程id
        order.setCourseTitle(courseInfoOrder.getTitle());
        order.setCourseCover(courseInfoOrder.getCover());
        order.setTeacherName(courseInfoOrder.getTeacherName());
        order.setTotalFee(courseInfoOrder.getPrice());
        order.setMemberId(memberId);
        order.setMobile(userInfoOrder.getMobile());
        order.setNickname(userInfoOrder.getNickname());
        order.setStatus(0);  //订单状态(0:未支付 1:已支付)
        order.setPayType(1);  //支付类型 ,微信1
        baseMapper.insert(order);
        //返回订单号
        return order.getOrderNo();
    }

上面用到了微服务
ucenterClient、eduClient 这两个服务类是其他服务的模块对象
点击查看

2.1 在调用端:

添加注解

@EnableDiscoveryClient//微服务注册的注解
@EnableFeignClients//微服务调用段的注解
  • 添加调用端的接口(该接口和服务端的接口一样)
@Component
@FeignClient(name="service-edu",fallback = UcenterClientImpl.class)
public interface EduClient {

    //根据课程id查询课程的基本信息
    @PostMapping("/eduservice/courseFront/getFrontCourseInfo/{courseId}")
    public CourseWebVoOrder getFrontCourseInfo(@PathVariable("courseId") String courseId);
}



实现类
@Component
public class EduClientImpl implements EduClient {
    @Override
    public CourseWebVoOrder getFrontCourseInfo(String courseId) {

        System.out.println("根据用户的id查询信息出错了");
        return null;
    }
}
@Component
@FeignClient(name="service-ucenter",fallback = UcenterClientImpl.class)
public interface UcenterClient {

    @PostMapping("/educenter/member/getUserInfoOrder/{id}")
    //根据用户的id查询用户的信息
    public UcenterMemberOrder getUserInfoOrder(@PathVariable("id") String id);
}


实现类
@Component
public class UcenterClientImpl implements UcenterClient {
    @Override
    public UcenterMemberOrder getUserInfoOrder(String id) {
        System.out.println("获取用户信息出错了");
        return null;
    }
}

2.2 服务端

在启动类上添加@EnableDiscoveryClient//注册服务

   //根据用户id获取用户的信息
    @PostMapping("/getUserInfoOrder/{id}")
    @ApiOperation("根据用户的id查询用户的信息")
    public UcenterMemberOrder getUserInfoOrder(@PathVariable String id){
        UcenterMember member = memberService.getById(id);
        UcenterMemberOrder memberOrder = new UcenterMemberOrder();
        //把member对象里面值复制给UcenterMemberOrder对象
        BeanUtils.copyProperties(member,memberOrder);
        return memberOrder;
    }
    //根据课程id查询课程信息
    @ApiOperation("根据课程id查询课程的详细信息")
    @PostMapping("getFrontCourseInfo/{courseId}")
    public CourseWebVoOrder getFrontCourseInfo(@PathVariable String courseId){
        CourseWebVo baseCourseInfo = courseService.getBaseCourseInfo(courseId);
        CourseWebVoOrder webVoOrder = new CourseWebVoOrder();
        BeanUtils.copyProperties(baseCourseInfo,webVoOrder);
        return webVoOrder;
    }

3. 前端部分

3.1 生成订单

import request from '@/utils/request'

export default {
    //生成订单
    createOrders(courseId) {
    return request({
      url: `/eduorder/order/createOrder/${courseId}`,
      method: 'post'
    })
  },
  //获取订单的信息
  getOrderInfo(orderId){
    return request({
      url: `/eduorder/order/getOrderInfo/${orderId}`,
      method: 'get'
    })
  }
}

在页面进行调用

    //创建订单  然后跳转到订单界面
   methods:{
    createOrders(){
      orderApi.createOrders(this.courseId).then(response=>{
        //获取返回的订单号
       
        //生成订单后跳转到订单显示页面
        this.$router.push({
          path:'/orders/'+response.data.data.orderId
        })
      })
    }
   }

在这里插入图片描述

<template>
    <div class="Page Confirm">
      <div class="Title">
        <h1 class="fl f18">订单确认</h1>
        <img src="~/assets/img/cart_setp2.png" class="fr">
        <div class="clear"></div>
      </div>
      <form name="flowForm" id="flowForm" method="post" action="">
        <table class="GoodList">
          <tbody>
          <tr>
            <th class="name">商品</th>
            <th class="price">原价</th>
            <th class="priceNew">价格</th>
          </tr>
          </tbody>
          <tbody>
          <!-- <tr>
            <td colspan="3" class="Title red f18 fb"><p>限时折扣</p></td>
          </tr> -->
          <tr>
            <td colspan="3" class="teacher">讲师:{{order.teacherName}}</td>
          </tr>
          <tr class="good">
            <td class="name First">
              <a target="_blank" :href="'https://localhost:3000/course/'+order.courseId">
                <img :src="order.courseCover"></a>
              <div class="goodInfo">
                <input type="hidden" class="ids ids_14502" value="14502">
                <a target="_blank" :href="'https://localhost:3000/course/'+ order.courseId">{{order.courseTitle}}</a>
              </div>
            </td>
            <td class="price">
              <p><strong>{{order.totalFee}}</strong></p>
              <!-- <span class="discName red">限时8折</span> -->
            </td>
            <td class="red priceNew Last"><strong>{{order.totalFee}}</strong></td>
          </tr>
          <tr>
            <td class="Billing tr" colspan="3">
              <div class="tr">
                <p><strong class="red">1</strong> 件商品,合计<span
                  class="red f20"><strong>{{order.totalFee}}</strong></span></p>
              </div>
            </td>
          </tr>
          </tbody>
        </table>
        <div class="Finish">
          <div class="fr" id="AgreeDiv">
            
            <label for="Agree"><p class="on"><input type="checkbox" checked="checked">我已阅读并同意<a href="javascript:" target="_blank">《谷粒学院购买协议》</a></p></label>
          </div>
          <div class="clear"></div>
          <div class="Main fl">
            <div class="fl">
              <a :href="'/course/'+order.courseId">返回课程详情页</a>
            </div>
            <div class="fr">
              <p><strong class="red">1</strong> 件商品,合计<span class="red f20"><strong
                id="AllPrice">{{order.totalFee}}</strong></span></p>
            </div>
          </div>
          <input name="score" value="0" type="hidden" id="usedScore">
          <button class="fr redb" type="button" id="submitPay" @click="toPay()">去支付</button>
          <div class="clear"></div>
        </div>
      </form>
    </div>
  </template>
  <script>
  import ordersApi from '@/api/order'
  export default {
      asyncData({ params, error }) {
          return ordersApi.getOrderInfo(params.oid)
              .then(response => {
                  return {
                      order: response.data.data.item
                  }
              })
      },
      methods:{
          //去支付
          toPay() {
              this.$router.push({path:'/pay/'+this.order.orderNo})
          }
      }
  }
  </script>
  

3.2 进行支付

3.2.1 准备工作

这里用到了尚学堂提供的免费测试接口

weixin:
  pay:
    #关联的公众号appid
    appid: wx74862e0dfcf69954
    #商户号
    partner: 1558950191
    #商户key
    partnerkey: T6m9iK73b0kn9g5v426MKfHQH7X8rKwb
    #回调地址
    notifyurl: http://guli.shop/api/order/weixinPay/weixinNotify

3.2.2 导入jar包

    <dependencies>
        <dependency>
            <groupId>com.github.wxpay</groupId>
            <artifactId>wxpay-sdk</artifactId>
            <version>0.0.3</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
    </dependencies>
  • 工具类HttpClient
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;
	}

}

  • 生成微信支付二维码接口
 @GetMapping("createNative/{orderNo}")
    public R createNative(@PathVariable String orderNo){
        //返回信息 包含二维码地址 还有其他信息
        Map<String,Object> map=payLogService.createNative(orderNo);
        return R.ok().data(map);
    }

调用的接口
 //生成二维码
    @Override
    public Map<String, Object> createNative(String orderNo) {
        try {
            //1. 根据订单号查询订单信息
            QueryWrapper<Order> wrapper = new QueryWrapper<>();
            wrapper.eq("order_no",orderNo);
            Order order = orderService.getOne(wrapper);
            //2. 使用map设置生成二维码需要的参数
            Map<String, String> m = new HashMap<>();
            m.put("appid","wx74862e0dfcf69954");
            m.put("mch_id", "1558950191");
            m.put("nonce_str", WXPayUtil.generateNonceStr());
            m.put("body", order.getCourseTitle()); //课程标题
            m.put("out_trade_no", orderNo); //订单号
            m.put("total_fee", order.getTotalFee().multiply(new BigDecimal("100")).longValue()+"");
            m.put("spbill_create_ip", "127.0.0.1");
            m.put("notify_url", "http://guli.shop/api/order/weixinPay/weixinNotify\n");
            m.put("trade_type", "NATIVE");
            //3. 发送httpclient请求,传递参数xml格式,微信支付提供的固定地址
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
            //设置xml格式的参数
            client.setXmlParam(WXPayUtil.generateSignedXml(m,"T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));
            client.setHttps(true);
            //执行post请求发送
            client.post();
            //4. 得到发送请求返回结果
            //返回内容,是使用xml格式返回
            String xml = client.getContent();
            //把xml格式转换map集合,把map集合返回
            Map<String,String> resultMap = WXPayUtil.xmlToMap(xml);

            //最终返回数据 的封装
            Map<String,Object> map = new HashMap<>();
            map.put("out_trade_no", orderNo);
            map.put("course_id", order.getCourseId());
            map.put("total_fee", order.getTotalFee());
            map.put("result_code", resultMap.get("result_code"));  //返回二维码操作状态码
            map.put("code_url", resultMap.get("code_url"));        //二维码地址
            return map;
        }catch (Exception e){
            throw new GuliException(20001,"生成二维码异常");
        }
    }
  • 查询订单状态
 //查询订单状态
    @ApiOperation("查询订单状态")
    @GetMapping("queryPayStatus/{orderNo}")
    public R queryPayStatus(@PathVariable String orderNo){
      Map<String,String> map=  payLogService.queryPayStatus(orderNo);
   if(map==null){
       return R.error().message("支付出错了");
   }
   //如果返回map里面不为空,通过map获取订单状态
   if(map.get("trade_state").equals("SUCCESS")){
       //添加记录到支付表里,更新订单表 订单状态
       payLogService.updateOrderStatus(map);
       return R.ok();

   }
   return R.ok().message("支付成功");
    }

调用的接口
  //查询订单支付状态
    @Override
    public Map<String, String> queryPayStatus(String orderNo) {
        try {
            //1、封装参数
            Map m = new HashMap<>();
            m.put("appid", "wx74862e0dfcf69954");
            m.put("mch_id", "1558950191");
            m.put("out_trade_no", orderNo);
            m.put("nonce_str", WXPayUtil.generateNonceStr());

            //2 发送httpclient
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
            client.setXmlParam(WXPayUtil.generateSignedXml(m,"T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));
            client.setHttps(true);
            client.post();

            //3 得到请求返回内容
            String xml = client.getContent();
            Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
            //6、转成Map再返回
            return resultMap;
        }catch(Exception e) {
            return null;
        }
    }

    //添加支付记录和更新订单状态
    @Override
    public void updateOrderStatus(Map<String, String> map) {
        //从map获取订单号
        String orderNo = map.get("out_trade_no");
        //根据订单号查询订单信息
        QueryWrapper<Order> wrapper = new QueryWrapper<>();
        wrapper.eq("order_no",orderNo);
        Order order = orderService.getOne(wrapper);

        //更新订单表订单状态
        if(order.getStatus().intValue() == 1) { return; }
        order.setStatus(1);//1代表已经支付
        orderService.updateById(order);

        //向支付表添加支付记录
        PayLog payLog = new PayLog();
        payLog.setOrderNo(orderNo);  //订单号
        payLog.setPayTime(new Date()); //订单完成时间
        payLog.setPayType(1);//支付类型 1微信
        payLog.setTotalFee(order.getTotalFee());//总金额(分)

        payLog.setTradeState(map.get("trade_state"));//支付状态
        payLog.setTransactionId(map.get("transaction_id")); //流水号
        payLog.setAttr(JSONObject.toJSONString(map));

        baseMapper.insert(payLog);
    }

3.2.3 前端整合

    //生成二维码的方法
    createNative(orderNo) {
      return request({
        url: `/eduorder/paylog/createNative/${orderNo}`,
        method: 'get'
      })
    },
    //查询订单状态
    queryPayStatus(orderNo){
      return request({
        url: `/eduorder/paylog/queryPayStatus/${orderNo}`,
        method: 'get'
      })
    },
  • 在页面上调用上面的方法
    在点击去支付 进行页面跳转
     methods:{
          //去支付
          toPay() {
              this.$router.push({path:'/pay/'+this.order.orderNo})
          }
      }

在这里插入图片描述

<template>
    <div class="cart py-container">
      <!--主内容-->
      <div class="checkout py-container  pay">
        <div class="checkout-tit">
          <h4 class="fl tit-txt"><span class="success-icon"></span><span class="success-info">订单提交成功,请您及时付款!订单号:{{payObj.out_trade_no}}</span>
          </h4>
          <span class="fr"><em class="sui-lead">应付金额:</em><em class="orange money">¥{{payObj.total_fee}}</em></span>
          <div class="clearfix"></div>
        </div>
        <div class="checkout-steps">
          <div class="fl weixin">微信支付</div>
          <div class="fl sao">
            <p class="red">请使用微信扫一扫。</p>
            <div class="fl code">
              <!-- <img id="qrious" src="~/assets/img/erweima.png" alt=""> -->
              <!-- <qriously value="weixin://wxpay/bizpayurl?pr=R7tnDpZ" :size="338"/> -->
              <qriously :value="payObj.code_url" :size="338"/>
              <div class="saosao">
                <p>请使用微信扫一扫</p>
                <p>扫描二维码支付</p>
              </div>
  
            </div>
  
          </div>
          <div class="clearfix"></div>
          <!-- <p><a href="pay.html" target="_blank">> 其他支付方式</a></p> -->
          
        </div>
      </div>
    </div>
  </template>

在这里插入图片描述

<script>
  import ordersApi from '@/api/order'
  export default {
       asyncData({ params, error }) {
           return ordersApi.createNative(params.pid)
              .then(response => {
                  return {
                        payObj: response.data.data
                      }
              })
       },
       data() {
           return {
               timer1:''
           }
       },
       //每隔三秒调用一次查询订单状态的方法
       mounted() {//页面渲染之后执行
          this.timer1 = setInterval(() => {
              this.queryOrderStatus(this.payObj.out_trade_no)
          },3000);
       },
       methods:{
           queryOrderStatus(orderNo) {
               ordersApi.queryPayStatus(orderNo)
                  .then(response => {
                       if (response.data.success) {
                          //支付成功,清除定时器
                          clearInterval(this.timer1)
                          //提示
                          this.$message({
                              type: 'success',
                              message: '支付成功!'
                          })
                          //跳转回到课程详情页面
                          this.$router.push({path: '/course/' + this.payObj.course_id})
                       }
                  })
           }
       }
  }
  </script>
  

上面代码加入了定时器,当订单支付状态变更,定时器注销

  • 请求域上的拦截器
// http response 拦截器
service.interceptors.response.use(
  response => {
    //debugger
    if (response.data.code == 28004) {
        console.log("response.data.resultCode是28004")
        // 返回 错误代码-1 清除ticket信息并跳转到登录页面
        //debugger
        window.location.href="/login"
        return
    }else{
      if (response.data.code !== 20000) {
        //25000:订单支付中,不做任何提示
        if(response.data.code != 25000) {
          Message({
            message: response.data.message || 'error',
            type: 'error',
            duration: 5 * 1000
          })
        }
      } else {
        return response;
      }
    }
  },
  error => {
    return Promise.reject(error.response)   // 返回接口返回的错误信息
});

为了显示支付状态为支付中。。。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值