SpringCloud+RabbitMQ微服务订单系统

mac2026-05-19  5

1.下单的时候,调用订单微服务系统的下单方法,首先,先给订单实体赋值,然后在向MQ发送消息,接收到MQ返回来的消息后,保存订单,在生成微信或支付宝的签名字符串

2.下单(购买)接口

@PostMapping("/payGoods") public Result payGoods(@RequestBody OrderSGoods orderSGoods, HttpServletRequest request) throws ParserConfigurationException, IOException, SAXException { //得到用户id Result result = jwtUtil.getUserId() ; if(!result.isFlag()){ return result ; } //用户id String userId = (String)result.getData() ; System.out.println(orderSGoods); //判断参数是否为空 if(orderSGoods==null){ return ResultUtil.error(StatusCode.ERROR,"对象不能为空") ; } if(StringUtils.isEmpty(orderSGoods.getArea())|| StringUtils.isEmpty(orderSGoods.getCity()) || StringUtils.isEmpty(orderSGoods.getDetail())|| StringUtils.isEmpty(orderSGoods.getMobile()) || StringUtils.isEmpty(orderSGoods.getProvince())|| StringUtils.isEmpty(orderSGoods.getStreet()) || StringUtils.isEmpty(orderSGoods.getUserName())||orderSGoods.getOrderShopModels().size()<1 ||orderSGoods.getTotalNum()<1||orderSGoods.getTotalPrice()<1|| StringUtils.isEmpty(orderSGoods.getChannel())){ return ResultUtil.error(StatusCode.ERROR,"参数不能为空") ; } //TODO 判断库存是否充足,从缓存中得库存 /****************赋值****************/ Date date = new Date() ; //订单商家表 List<OrderShopModel> orderShops = orderSGoods.getOrderShopModels() ; //订单个数,前期只有一个订单 int len = orderShops.size() ; List<OrderSave> orderSaves = new ArrayList<>(); //TODO 订单总金额 Double money = orderSGoods.getTotalPrice(); ; //订单编号 String orderNo = Long.toString(idWorker.nextId())+"0"; for(int i =0;i<len;i++){ //订单id String id = Long.toString(idWorker.nextId()); //订单表 Order order = new Order() ; order.setState(OrderPayConstant.STATE_WAIT_PAY); order.setUserId(userId); order.setStateDes("待付款"); order.setGenTime(date); order.setId(id); order.setTotalNum(orderSGoods.getTotalNum()); order.setTotalPrice(orderSGoods.getTotalPrice()); order.setOrderNo(orderNo); order.setUserName(orderSGoods.getUserName()); order.setOrderDesc("购买商品"); order.setChannel(orderSGoods.getChannel()); order.setType(OrderPayConstant.TYPE_ORDER_BUY); //订单商家表 OrderShopModel orderShopModel = orderShops.get(0) ; OrderShop orderShop = new OrderShop(); orderShop.setGenTime(date); orderShop.setId(Long.toString(idWorker.nextId())); orderShop.setOrderId(id); orderShop.setPostFee(orderShopModel.getPostFee()); if(StringUtils.isNotEmpty(orderShopModel.getRemark())){ orderShop.setRemark(orderShopModel.getRemark()); } orderShop.setShopId(orderShopModel.getShopId()); orderShop.setShopName(orderShopModel.getShopName()); orderShop.setTotalFee(orderShopModel.getTotalFee()); //判断商品信息是否为空 List<GoodsModel> goodsModels = orderShopModel.getGoodsModels() ; if(goodsModels.size()<1){ return ResultUtil.error(StatusCode.ERROR,"商品信息不能为空"); } //商品详情表 List<OrderDetail> orderDetails = new ArrayList<>() ; for(GoodsModel o : goodsModels){ OrderDetail orderDetail = new OrderDetail() ; orderDetail.setId(Long.toString(idWorker.nextId())); orderDetail.setGenTime(date); orderDetail.setImages(o.getImages()); orderDetail.setNum(o.getNum()); orderDetail.setOrderId(id); orderDetail.setPrice(o.getPrice()); orderDetail.setSkuId(o.getSkuId()); orderDetail.setTitle(o.getTitle()); orderDetail.setSpuId(o.getSpuId()); orderDetail.setDes(o.getDes()); orderDetails.add(orderDetail) ; } //订单地址 OrderAddress orderAddress = new OrderAddress() ; orderAddress.setId(Long.toString(idWorker.nextId())); orderAddress.setArea(orderSGoods.getArea()); orderAddress.setCity(orderSGoods.getCity()); orderAddress.setUserName(orderSGoods.getUserName()); orderAddress.setDetail(orderSGoods.getDetail()); orderAddress.setGenTime(date); orderAddress.setMobile(orderSGoods.getMobile()); orderAddress.setOrderId(id); orderAddress.setProvince(orderSGoods.getProvince()); orderAddress.setStreet(orderSGoods.getStreet()); orderAddress.setUpdateTime(date); OrderSave orderSave = new OrderSave() ; orderSave.setOrder(order); orderSave.setOrderAddress(orderAddress); orderSave.setOrderDetails(orderDetails); orderSave.setOrderShop(orderShop); orderSaves.add(orderSave) ; //向RabbitMQ发送消息,然后在保存到数据库中;这样可以更好的应对大量订单的情况,做到缓冲的作用,提高系统响应 orderSender.send(JSON.toJSONString(orderSaves)); //TODO 计算金额,根据商品类型id去查询商品,得到商品金额 } //TODO 修改库存,在下订单的时候就修改库存,这样在支付成功后回调那,就不用再向商品系统发送消息去修改库存了 // 支付渠道渠道 String channel = orderSGoods.getChannel(); //生成支付宝、微信签名 Result rs = getSign(channel,orderNo,money,request); return rs; }

3.向MQ发送消息

package com.laxun.order.mq.order; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.TypeReference; import com.laxun.order.model.OrderSave; import com.laxun.order.mq.configure.CommonOrderMq; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.Message; import org.springframework.amqp.core.MessageBuilder; import org.springframework.amqp.core.MessageProperties; import org.springframework.amqp.rabbit.connection.CorrelationData; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; /** 生成订单发送消息 */ @Component @Slf4j public class OrderSender implements RabbitTemplate.ConfirmCallback{ @Autowired private RabbitTemplate rabbitTemplate; /** * 发送消息 * @param msg 订单内容,是json字符串 * */ @Transactional public void send(String msg) { System.out.println(">>>>>>订单微服务:向MQ发送消息>>>>>>" + msg); ArrayList<OrderSave> orderSaves = JSON.parseObject(msg, new TypeReference<ArrayList<OrderSave>>(){}); // 封装消息 Message message = MessageBuilder.withBody(msg.getBytes()) .setContentType(MessageProperties.CONTENT_TYPE_JSON).setContentEncoding("utf-8").setMessageId(orderSaves.get(0).getOrder().getId()) .build(); // 构建回调返回的数据(消息id) this.rabbitTemplate.setMandatory(true); this.rabbitTemplate.setConfirmCallback(this); CorrelationData correlationData = new CorrelationData(msg); rabbitTemplate.convertAndSend(CommonOrderMq.ORDER_EXCHANGE, CommonOrderMq.ORDER_ROUTING_KEY, message, correlationData); } // 生产消息确认机制 生产者往服务器端发送消息的时候,采用应答机制 @Override public void confirm(CorrelationData correlationData, boolean ack, String cause) { String jsonString = correlationData.getId(); System.out.println("消息id:" + correlationData.getId()); if (ack) { log.info(">>>>>>使用MQ消息确认机制确保消息一定要投递到MQ中成功>>>>>>"); return; } JSONObject jsonObject = JSONObject.parseObject(jsonString); // 生产者消息投递失败的话,采用递归重试机制 send(jsonObject.toJSONString()); log.info(">>>>>>使用MQ消息确认机制投递到MQ中失败>>>>>>"); } }

4,接收MQ返回的消息,同时保存订单

package com.laxun.order.mq.order; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; import com.laxun.lxcommon.entity.order.Order; import com.laxun.order.model.OrderSave; import com.laxun.order.mq.configure.CommonOrderMq; import com.laxun.order.service.OrderService; import com.rabbitmq.client.Channel; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** 接收订单消息队列中的消息 */ @Component @Slf4j public class OrderReceiver { @Autowired OrderService orderService; @RabbitListener(queues = CommonOrderMq.ORDER_QUEUE) public void process(Message message, Channel channel) throws IOException { try { //内容字符串 String msg = new String(message.getBody(), "UTF-8"); //将消息转为list集合,得到订单信息 ArrayList<OrderSave> orderSaves = JSON.parseObject(msg, new TypeReference<ArrayList<OrderSave>>(){}); //判断订单信息是否为空 if (orderSaves.size()==0) { log.error(">>>>>>订单信息不能为空>>>>>>", orderSaves); basicNack(message, channel); return; } //查看订单信息是否保存过 if (isProcess(orderSaves)) { log.error(">>>>>>订单已存在>>>>>>", orderSaves); basicNack(message, channel); return; } //保存订单 orderService.addGoods(orderSaves); basicNack(message,channel); System.out.println(">>>>>>订单保存成功>>>>>>"); } catch (Exception e) { e.printStackTrace(); basicNack(message, channel); } } //告诉服务器收到这条消息 已经被我消费了 可以在队列删掉 这样以后就不会再发了 // 否则消息服务器以为这条消息没处理掉 后续还会在发 private void basicNack(Message message, Channel channel) throws IOException { channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false); } /** * 判断订单是否保存过 * @param orderSave * @return */ public boolean isProcess(List<OrderSave> orderSave){ boolean flag = true ; for(OrderSave o:orderSave){ //订单 Order order = o.getOrder() ; //订单编号 String orderNo = order.getOrderNo() ; //根据订单编号查询订单是否存在 Order od = orderService.getOrderByOrderNo(orderNo) ; if(od==null){ flag = false ; break; } } return flag ; } }

5.生成支付宝、微信的签名字符串

/** * 返回支付需要的签名 * @param channel 支付渠道 * @param orderNo 订单编号 * @param money 金额 * @param request * @return * @throws ParserConfigurationException * @throws IOException * @throws SAXException */ public Result getSign(String channel,String orderNo,Double money,HttpServletRequest request) throws ParserConfigurationException, IOException, SAXException { if("0".equals(channel)){ // 余额支付 }else if("1".equals(channel)){ //如果是微信支付 Map<String, String> m = new HashMap<String, String>(); m.put("appid", WxConfig.APPID);// 公众账号ID m.put("mch_id", WxConfig.MUCHID);// 商户号 m.put("nonce_str", RandomStringGenerator.getRandomStringByLength(32));//设备号 m.put("body", "辣讯商品支付");// 商品描述/名称 m.put("out_trade_no", orderNo);// 商户订单号编号 m.put("total_fee",String.valueOf((int)(money*100)));//总金额 m.put("spbill_create_ip", RandomStringGenerator.getIpAddress(request));// 终端IP m.put("notify_url", WxConfig.NOTIFY_URL);// 回调地址 m.put("trade_type", "APP");// 交易类型 //参数签名,待传key m.put("sign", PaymentKit.createSign(m, WxConfig.SECRETKEY)); String xmlStr = PaymentApi.pushOrder(m); System.out.println("调用支付接口xml:"+xmlStr); Map<String, Object> map = XMLParser.getMapFromXML(xmlStr); if("SUCCESS".equals(map.get("result_code"))){ Map<String,String> paySignReqHandler = new HashMap<String,String>(); paySignReqHandler.put("appid", WxConfig.APPID); paySignReqHandler.put("partnerid", WxConfig.MUCHID); paySignReqHandler.put("prepayid", map.get("prepay_id").toString()); paySignReqHandler.put("package", "Sign=WXPay"); paySignReqHandler.put("noncestr", map.get("nonce_str").toString()); paySignReqHandler.put("timestamp", String.valueOf(System.currentTimeMillis()/1000)); paySignReqHandler.put("sign", PaymentKit.createSign(paySignReqHandler, WxConfig.SECRETKEY)); return ResultUtil.success(StatusCode.OK,"下单成功",paySignReqHandler); } }else if("2".equals(channel)){ //支付宝支付 //初始化请求客户端,其中封装了签名、请求、验签的功能 AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, "json", AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE); //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay AlipayTradeAppPayRequest alipayrequest = new AlipayTradeAppPayRequest(); //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。 AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); model.setBody("辣讯商品支付");//对一笔交易的具体描述信息 model.setSubject("辣讯商品支付");//商品的标题/交易标题/订单标题/订单关键字等。 model.setOutTradeNo(orderNo);//商户网站唯一订单号 model.setTimeoutExpress("30m");//该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15dm-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 该参数数值不接受小数点, 如 1.5h,可转换为 90m。 model.setTotalAmount(money.toString());//金额 model.setProductCode("QUICK_MSECURITY_PAY");//销售产品码,商家和支付宝签约的产品码 alipayrequest.setBizModel(model); alipayrequest.setNotifyUrl(AlipayConfig.notify_url);//回调地址 try { //这里和普通的接口调用不同,使用的是sdkExecute AlipayTradeAppPayResponse response = alipayClient.sdkExecute(alipayrequest); System.out.println(response.getBody());//就是orderString 可以直接给客户端请求,无需再做处理。 return ResultUtil.success(StatusCode.OK,"下单成功",response.getBody()); } catch (AlipayApiException e) { e.printStackTrace(); } } return ResultUtil.error(StatusCode.ERROR,"创建订单失败") ; }

 

最新回复(0)