订单实现总结-redis实现订单监听

37 篇文章 0 订阅
8 篇文章 0 订阅

遇到的问题:

一,让订阅程序随着应用程序的启动而启动。

刚开始想到的几种方法
1,让spring注入这个订阅程序,
但是发现Spring会注入这个类,但是不会运行它的main方法。

2,将这个订阅程序作为一个监听器配置在web.xml中,这样就可以tomcat启动的时候一起启动这个订阅程序了。
但是订阅程序是可以启动了,但是tomcat却启动不起来了。
好像是被僵住了,没找到报错信息。不知道怎么回事,这种方式放弃了。

然后百度到一种。
如同这篇:tomcat启动时将缓存放入redis中。
https://blog.csdn.net/nightliar/article/details/78593068#commentBox

我的

订单订阅程序:

package com.wjh.listener;

import com.wjh.dao.RedisDao;
import com.wjh.dao.impl.RedisDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import javax.annotation.PostConstruct;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.util.List;

/**
 * Author:   17976
 * Date:     2019/2/23 22:29
 * Description: redis订阅程序
 */
@Configuration
public class Subscriber {
    @Autowired
    private RedisDao redisDao;

    @PostConstruct
    public void doSubscribe() {
        new Thread() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(3*1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Jedis jedis=redisDao.getJedis();
                    jedis.auth("flower");
//        config(jedis);
//        只订阅patten匹配的超时事件
                    System.out.println("开始订阅..........");
                    jedis.psubscribe(new KeyExpiredListener(), "__key*@0__:expired");
                    break;
                }
            }
        }.start();
    }
    private static void config(Jedis jedis) {
        String parameter = "notify-keyspace-events";
        List<String> notify = jedis.configGet(parameter);
        if (notify.get(1).equals("")) {
            jedis.configSet(parameter, "Ex"); //过期事件
        }
    }
}

@Configuration的作用类似于配置一个spring-bean.xml中的标签的作用,主要用于Bean的注入,放置在类上。
https://blog.csdn.net/entomb/article/details/81151533
被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。
在这里插入图片描述
转载:
https://www.jianshu.com/p/98cf7d8b9ec3
监听(发布)程序

package com.wjh.listener;

import com.wjh.bean.TOrder;
import com.wjh.dao.mapper.TOrderMapper;
import com.wjh.util.Constants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.JedisPubSub;

/**
 * Author:   17976
 * Date:     2019/2/23 21:34
 * Description: 监听redis key是否过期
 */
@Component
public class KeyExpiredListener extends JedisPubSub {
    @Autowired
    private TOrderMapper orderMapper;
    //订阅的频道
    @Override
    public void onPSubscribe(String pattern, int subscribedChannels) {
//        super.onPSubscribe(pattern, subscribedChannels);
        System.out.println("onPSubscribe " + pattern + " " + subscribedChannels);
    }

//订阅的信息
    @Override
    public void onPMessage(String pattern, String channel, String message) {
        System.out.println("onPMessage pattern -->" + pattern + "-->channel: " + channel + "message--> " + message);
        if (message.startsWith("order")){//订单如果超时,查询数据库,如果state为超时未支付,则交易关闭
            TOrder order=orderMapper.selectByPrimaryKey(message);
            String orderId=order.getId();
            System.out.println("过期订单----"+orderId);
            if (order.getState().equals(Constants.ORDER_PAY_TIMEOUT)){
                order.setState(Constants.ORDER_CLOSED);//超时未支付,交易关闭
            }
        }
    }
}

其它需要的几个类和在Spring中的配置,参考
Jedis发布订阅:
https://blog.csdn.net/flower_CSDN/article/details/87898888
redis客户端发布订阅详解:
https://blog.csdn.net/flower_CSDN/article/details/87907691

将订单存入mysql之前先存入redis,并设置订单的过期时间,这样到了过期时间之后,这个orderid的key的过期事件就会被KeyExpiredListener捕捉到,通过监听器中的onPMessage输出订阅到的信息。

 public void addOrder(TOrder order) {
        redisDao.setEx("order"+order.getId(), JSON.toJSONString(order),Constants.ORDER_PAY_TIMEOUT);
        orderMapper.insert(order);
    }

生成唯一不重复的订单号

/**
     * 生成的订单长度为24位
     * date+uuidHashCode
     * 例如:
     * date:20190226155041
     * orderid:201902261550412018896709
     * @return
     */
public String generateOrderId() {
        String orderId="";
        Integer uuidHashCode = UUID.randomUUID().toString().hashCode();
        if (uuidHashCode < 0) {
            uuidHashCode = uuidHashCode * (-1);
        }
        String date = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        orderId=date + uuidHashCode;
        return orderId;
    }

格式化价格

 /**
     *
     * @param bd 要传入的BigDecimal价格对象
     * @param num   要保留的小数位数,例如num=2
     * @return
     */
    public static BigDecimal formatPrice(BigDecimal bd,int num){
        if(bd == null || num < 0){
            return null;
        }
        bd = bd.setScale(num, BigDecimal.ROUND_HALF_UP);//BigDecimal.ROUND_HALF_UP四舍五入
        return bd;
    }

还有订单和订单项的关系,一对多
在点击结算的时候,传入的订单项应该是一个数组,对应同一个orderId

流程:
在这里插入图片描述

package com.wjh.controller;

import com.alibaba.fastjson.JSON;
import com.wjh.bean.TBook;
import com.wjh.bean.TOrder;
import com.wjh.bean.TOrderItem;
import com.wjh.bean.TUser;
import com.wjh.service.IBookService;
import com.wjh.service.IOrderItemService;
import com.wjh.service.IOrderServie;
import com.wjh.util.Constants;
import com.wjh.util.ShopUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Author:   17976
 * Date:     2019/2/25 18:50
 * Description:
 */
public class OrderController {
    @Autowired
    private IOrderServie orderService;
    @Autowired
    private IOrderItemService orderItemService;
    @Autowired
    private IBookService bookService;
    /**
     * 点立即付款的时候就生成订单信息,存入数据库
     * 先生成订单
     * 再生成订单项
     *
     * 这里传入的参数orderItem应该是一个json数组格式的,因为一个订单中有多个订单项,对应的orderId只有一个
     * @return
     */
    @RequestMapping(value = "toOrder",method =RequestMethod.GET )
    public String addOrder(String orderItem, HttpServletRequest request){
        List<TOrderItem> orderItemList= JSON.parseArray(orderItem,TOrderItem.class);
        TOrder order=new TOrder();
        String orderId=orderService.generateOrderId();
        order.setId(orderId);
        HttpSession session=request.getSession();
        TUser user=(TUser)session.getAttribute("user");
        order.setUid(user.getId());
        order.setState(Constants.ORDER_WAIT_ALIPAY);//待支付,等支付完毕之后设置为1:待发货 超时未支付设置为已关闭,同时将该订单对应的订单项从订单表中删除
        /**
         * 循环将orderItem添加到数据库中
         */
        float sum=0;
        for (TOrderItem tOrderItem:orderItemList){
            tOrderItem.setOrderid(orderId);
            //将float格式的价格转换为两位小数
            tOrderItem.setPrice(ShopUtil.formatPrice(new BigDecimal(tOrderItem.getPrice()),2).floatValue());
            orderItemService.addOrderItem(tOrderItem);
            sum+=tOrderItem.getPrice();
        }
        /**
         * 订单价格为个订单项的总和
         * BigDecimal.ROUND_HALF_UP表示采用"四舍五入"的模式处理价格
         * 保留两位小数
         */
        BigDecimal bd=new BigDecimal(sum);
        order.setAmt(bd.setScale(2,BigDecimal.ROUND_HALF_UP));
        orderService.addOrder(order);
        /**
         * 存入数据库之后应该查出当前的订单信息,显示到前台,跳转到订单详情页
         * 订单详情页:
         *  订单信息:
         *      订单中的订单项信息:
         *          订单项中的商品信息
         */
        //订单信息
        TOrder tOrder=orderService.queryOrderByOrderid(orderId);
        request.setAttribute("order",tOrder);
        //订单项信息
        List<TOrderItem> orderItems=orderItemService.OrderItemList(orderId);
        Map orderItemMap=new HashMap<TOrderItem,TBook>();
        for (TOrderItem tOrderItem:orderItems){
            TBook book=bookService.selectBookById(tOrderItem.getBookid());
            orderItemMap.put(tOrderItem,book);
        }
        return "order/orderDetail";
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值