• 82--JT项目20(订单模块实现/ThreadLocal本地线程变量/Quartz框架)


    1.京淘权限设计

    1.1 业务说明

    当用户在不登录的条件下,不允许访问购物车/订单等受限的系统.并且重定向到用户的登录页面.
    问题:
    1.如何校验用户是否登录? 通过Cookie /Redis
    2.如何拦截用户的请求呢? 拦截器设定.

    1.2 拦截器实现用户权限校验

    1.2.1 SpringMVC调用原理图

    说明:通过图中的分析 handler处理器负责Controller之后的所有的业务处理.

    在这里插入图片描述

    1.2.2 mvc拦截器执行的示意图

    image-20200824205722705

    1.2.3编辑拦截器配置文件

    package com.jt.config;
    
    import com.jt.handler.UserInterceptor;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    @Configuration
    public class MvcConfigurer implements WebMvcConfigurer{//web项目中的web.xml配置文件
    	@Autowired
    	private UserInterceptor userInterceptor;
    
    	//开启匹配后缀型配置
    	@Override
    	public void configurePathMatch(PathMatchConfigurer configurer) {
    		
    		configurer.setUseSuffixPatternMatch(true);
    	}
    
    	//添加拦截器的配置
    	@Override
    	public void addInterceptors(InterceptorRegistry registry) {
    		//拦截购物车和订单模块
    		registry.addInterceptor(userInterceptor)
    				.addPathPatterns("/cart/**","/order/**");
    	}
    }
    
    

    1.2.4 定义拦截器

    package com.jt.handler;
    
    import com.jt.pojo.User;
    import com.jt.util.CookieUtil;
    import com.jt.util.ObjectMapperUtil;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.HandlerInterceptor;
    import redis.clients.jedis.JedisCluster;
    
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    //拦截器的类(业务)      拦截器的配置文件(拦截什么请求)
    @Component
    public class UserInterceptor implements HandlerInterceptor {
    
        private static final String TICKET = "JT_TICKET";
        private static final String JTUSER = "JT_USER";
        @Autowired
        private JedisCluster jedisCluster;
    
        /**
         *  实现pre的方法
         *  返回值说明:
         *          return  false 表示拦截 需要配合重定向一齐使用
         *          return  ture  表示放行
         *  需求1: 如果用户没有登录,则重定向到系统登录页面
         *  判断条件: 如何判断用户是否登录.  1.检查Cookie中是否有记录   2.Redis中是否有记录.
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
            Cookie cookie = CookieUtil.getCookieByName(request, TICKET);
            if(cookie != null){ //不为null.则表示用户可能登录.
                String ticket = cookie.getValue(); //cookie中存储的是Redis的key ticket密钥
                if(jedisCluster.exists(ticket)){
                    return true;
                }else{
                    //Cookie中的记录与Redis中的记录不一致.应该删除Cookie中的数据.
                    CookieUtil.deleteCookie(TICKET, "/", "jt.com",response);
                }
           }
    
            response.sendRedirect("/user/login.html");
            return false;   //表示拦截
        }
    }
    
    
    

    1.2.5 拦截器与AOP使用场景说明

    1.检查是否用到Request/Response对象,如果需要使用则建议使用拦截器.
    2.看具体业务功能. 具体业务具体分析.

    1.3 动态获取当前用户ID

    1.3.1 业务描述

    当用户登录之后,点击购物车/订单模块时需要动态的获取userID.如何实现???
    实现方式:
    1).基于Request对象的方式实现数据传参
    2).基于线程实现数据传参

    1.3.2 利用Request实现数据传参

    1.3.2.1 编辑拦截器

    package com.jt.handler;
    
    import com.jt.pojo.User;
    import com.jt.util.CookieUtil;
    import com.jt.util.ObjectMapperUtil;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.HandlerInterceptor;
    import redis.clients.jedis.JedisCluster;
    
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    //拦截器的类(业务)      拦截器的配置文件(拦截什么请求)
    @Component
    public class UserInterceptor implements HandlerInterceptor {
    
        private static final String TICKET = "JT_TICKET";
        private static final String JTUSER = "JT_USER";
        @Autowired
        private JedisCluster jedisCluster;
    
        /**
         *  实现pre的方法
         *  返回值说明:
         *          return  false 表示拦截 需要配合重定向一齐使用
         *          return  ture  表示放行
         *  需求1: 如果用户没有登录,则重定向到系统登录页面
         *  判断条件: 如何判断用户是否登录.  1.检查Cookie中是否有记录   2.Redis中是否有记录.
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
            Cookie cookie = CookieUtil.getCookieByName(request, TICKET);
            if(cookie != null){ //不为null.则表示用户可能登录.
                String ticket = cookie.getValue(); //cookie中存储的是Redis的key ticket密钥
                if(jedisCluster.exists(ticket)){
    
                    //如果redis中的数据存在,则说明用户已经登录.可以放行请求.
                    //获取真实的用户信息
                    String userJSON = jedisCluster.get(ticket);
                    //将json转化为对象
                    User user = ObjectMapperUtil.toObject(userJSON, User.class);
                    request.setAttribute(JTUSER, user);
                    return true;
                }else{
                    //Cookie中的记录与Redis中的记录不一致.应该删除Cookie中的数据.
                    CookieUtil.deleteCookie(TICKET, "/", "jt.com",response);
                }
           }
    
            response.sendRedirect("/user/login.html");
            return false;   //表示拦截
        }
    }
    

    1.3.2.2 编辑CartController

    在这里插入图片描述

    1.4 ThreadLocal介绍

    1.4.1 业务说明

    说明:如果利用Request对象的方式进行数据的传参,一般只能在Controller中进行动态的数据接收.
    如果在业务执行过程中需要该数据,则通过参数的形式继续向下传递.导致接口方法中的参数个数较多.
    虽然该写法没有任何的问题. 该操作是否可以优化???

    在这里插入图片描述

    1.4.2ThreadLocal说明

    名字: 本地线程变量
    作用: 在当前线程内,实现数据的共享.

    在这里插入图片描述

    1.4.3 ThreadLocal工具API

    package com.jt.util;
    
    import com.jt.pojo.User;
    
    public class UserThreadLocal {
    
        //定义本地线程变量
        private static  ThreadLocal<User> threadLocal = new ThreadLocal<>();
        //定义数据新增的方法
    
        public   static  void set(User user){
            threadLocal.set(user);
        }
        //获取数据的方法
    
        public  static  User get(){
            return  threadLocal.get();
        }
        //移除方法 ,使用threadlocal时切记将数据移除,否则极端条件下,容易产生内存泄露
        public static  void remove(){
            threadLocal.remove();
        }
    
    }
    

    1.4.4 实现用户数据获取

    1).将数据保存到ThreadLocal中,在拦截器中进行设置

    在这里插入图片描述

    2).动态获取数据

    在这里插入图片描述

    1.4.5 关于Dubbo中的ThreadLocal说明

    问题: 利用Dubbo框架从Controller能否向Service利用ThreadLocal传递数据???
    答案: 不可以
    原因: ThreadLocal只适用与单个项目内使用.不适合多系统调用.只能在单体架构中使用

    image-20200824211004589

    2.京淘订单业务实现

    2.1 订单项目创建

    2.1.1构建项目

    在这里插入图片描述

    2.1.2 添加继承/依赖/插件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>jt</artifactId>
            <groupId>com.jt</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>jt-order</artifactId>
        <!--添加依赖-->
        <dependencies>
            <dependency>
                <groupId>com.jt</groupId>
                <artifactId>jt-common</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
        </dependencies>
        <!-- 插件 用来打包-->
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    

    2.1.3 编辑POJO对象

    Order对象

    package com.jt.pojo;
    
    
    import java.util.Date;
    import java.util.List;
    
    import com.baomidou.mybatisplus.annotation.TableField;
    import com.baomidou.mybatisplus.annotation.TableId;
    import com.baomidou.mybatisplus.annotation.TableName;
    
    import lombok.Data;
    import lombok.experimental.Accessors;
    
    @TableName("tb_order")
    @Data
    @Accessors(chain=true)
    public class Order extends BasePojo{
    	@TableField(exist=false)	//入库操作忽略该字段
    	private OrderShipping orderShipping;
    								//封装订单商品信息  一对多
    	@TableField(exist=false)	//入库操作忽略该字段
    	private List<OrderItem> orderItems;
    	
    	@TableId
        private String orderId;//订单id =用户登录id+当前时间戳
        private String payment;
        private Integer paymentType;
        private String postFee;
        private Integer status;
        private Date paymentTime;
        private Date consignTime;
        private Date endTime;
        private Date closeTime;
        private String shippingName;
        private String shippingCode;
        private Long userId;
        private String buyerMessage;
        private String buyerNick;
        private Integer buyerRate;
    
    }
    

    OrderItem对象

    package com.jt.pojo;
    
    
    import java.util.Date;
    import java.util.List;
    
    import com.baomidou.mybatisplus.annotation.TableId;
    import com.baomidou.mybatisplus.annotation.TableName;
    
    import lombok.Data;
    import lombok.experimental.Accessors;
    @TableName("tb_order_item")
    @Data
    @Accessors(chain=true)
    public class OrderItem extends BasePojo{
    
    
    	@TableId
        private String orderId;
    
        private String itemId;
    
        private Integer num;
    
        private String title;
    
        private Long price;
    
        private Long totalFee;
    
        private String picPath;
    }
    

    OrderShipping对象

    package com.jt.pojo;
    
    
    import java.util.Date;
    import java.util.List;
    
    import com.baomidou.mybatisplus.annotation.TableId;
    import com.baomidou.mybatisplus.annotation.TableName;
    
    import lombok.Data;
    import lombok.experimental.Accessors;
    @TableName("tb_order_shipping")
    @Data
    @Accessors(chain=true)
    public class OrderShipping extends BasePojo{
    	
    	@TableId
        private String orderId;
    
        private String receiverName;
    
        private String receiverPhone;
    
        private String receiverMobile;
    
        private String receiverState;
    
        private String receiverCity;
    
        private String receiverDistrict;
    
        private String receiverAddress;
    
        private String receiverZip;
        
    }
    

    2.1.4 编辑OrderService接口

    在这里插入图片描述

    2.1.5 订单提供者创建

    在这里插入图片描述

    2.2 订单确认页面跳转

    2.2.1 业务需求

    1.当在购物车中点击去结算操作时应该跳转到订单的确认页面. order-cart.jsp
    2.应该展现用户的全部的购物车信息. ${carts}

    在这里插入图片描述

    2.2.2 编辑OrderController

    package com.jt.controller;
    
    import com.alibaba.dubbo.config.annotation.Reference;
    import com.jt.pojo.Cart;
    import com.jt.service.DubboCartService;
    import com.jt.util.UserThreadLocal;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import java.util.List;
    
    //1.业务名称与Controller对应即可
    @Controller
    @RequestMapping("/order")
    public class OrderController {
    
        //2.添加接口
        @Reference //使用dubbo的包
        private DubboCartService cartService;
    
        /**
         * 跳转订单确认页面
         * 1.url:http://www.jt.com/order/create.html
         * 2.参数: 没有参数 null
         * 3.返回值: order-cart
         * 4.页面取值  {carts}  需要查询购物车信息.,给页面返回
         */
        @RequestMapping("create")
        public String create(Model model){
    
            Long userId = UserThreadLocal.get().getId();
            List<Cart> cartList = cartService.findCartList(userId);
            model.addAttribute("carts",cartList);
            return "order-cart";
        }
    
    
    }
    

    2.2.3 页面效果展现

    image-20200824211655494

    2.3 关于SpringMVC中页面赋值说明

    2.3.1 简单参数传递

    1).html标签

    <html>
    	<input type="text" name="name" />
    	<input type="text" name="age" />
    </html>
    

    2).Controller中的方法

    public xxxx saveUser(String name,int age){
    }
    

    2.3.2 利用对象的方式接收参数

    1).html标签

    <html>
    	<input type="text" name="name" />
    	<input type="text" name="age" />
    </html>
    

    2).Controller中的方法

    public xxxx saveUser(User user){ //名称需要和属性一致...
    }
    

    2.3.3 为对象的引用赋值

    目的:该方法可以有效的解决重名参数提交的问题. 为对象的引用赋值.
    1).html标签

    <html>
    	<input type="text" name="name" value="二郎神"/>
    	<input type="text" name="age"  value="2000"/>
    	<input type="text" name="dog.name" value="哮天犬"/>
    	<input type="text" name="dog.age"  value="9000"/>
    </html>
    

    2).Controller中的方法

    public xxxx saveUser(User user){ //名称需要和属性一致...
    	
    }
    public class User{
    	private Dog  dog; //为对象添加一个引用
    	private String name; 
    	private Integer age;
    }
    
    public class Dog{
    	private String name;
    	private Integer age;
    }
    

    2.4 完成订单入库

    2.4.1 页面表单说明

    <form id="orderForm" class="hide">
        <input type="hidden" name="paymentType" value="1"/>
        <c:forEach items="${carts}" var="cart" varStatus="status">
            <c:set var="totalPrice"  value="${ totalPrice + (cart.itemPrice * cart.num)}"/>
            <input type="hidden" name="orderItems[${status.index}].itemId" value="${cart.itemId}"/>
            <input type="hidden" name="orderItems[${status.index}].num" value="${cart.num }"/>
            <input type="hidden" name="orderItems[${status.index}].price" value="${cart.itemPrice}"/>
            <input type="hidden" name="orderItems[${status.index}].totalFee" value="${cart.itemPrice * cart.num}"/>
            <input type="hidden" name="orderItems[${status.index}].title" value="${cart.itemTitle}"/>
            <input type="hidden" name="orderItems[${status.index}].picPath" value="${cart.itemImage}"/>
        </c:forEach>
        <input type="hidden" name="payment" value="<fmt:formatNumber groupingUsed="false" maxFractionDigits="2" minFractionDigits="2" value="${totalPrice/100 }"/>"/>
        <input type="hidden" name="orderShipping.receiverName" value="陈晨"/>
        <input type="hidden" name="orderShipping.receiverMobile" value="13800807944"/>
        <input type="hidden" name="orderShipping.receiverState" value="北京"/>
        <input type="hidden" name="orderShipping.receiverCity" value="北京"/>
        <input type="hidden" name="orderShipping.receiverDistrict" value="海淀区"/>
        <input type="hidden" name="orderShipping.receiverAddress" value="清华大学"/>
    </form>
    

    2.4.2 POJO说明

    说明:利用Order对象封装了其他2张表的数据.,所以参数使用Order对象封装即可.

    在这里插入图片描述

    2.4.3 页面URL分析

    1).post提交
    在这里插入图片描述
    2).参数提交
    在这里插入图片描述
    3).返回值结果
    在这里插入图片描述

    2.4.4 编辑OrderController

    /**
        * 1.实现订单入库
        *   url:http://www. jt. com/order/submit
        *   参数:整个form表单利用order对象 接收
        *   返回值: SysResult对象 返回orderId
        *   业务:订单入库时应该入库3张表记录. order orderShipping orderItems
        *   orderId由登录用户id+当前时间戳手动拼接.
        *   并且要求三个对象的主键值相同.
        */
    @RequestMapping("/submit")
    @ResponseBody
    public SysResult submit(Order order,HttpServletRequest request){
        //获取用户的id
        User user = (User) request.getAttribute("JT_USER");
        Long userId = user.getId();
        order.setUserId(userId);	//将userId进行赋值操作.
        //订单入库操作
        String orderId =dubboOrderService.saveOrder(order);
        if (StringUtils.isEmpty(orderId)){
            return  SysResult.fail();
        }
        return  SysResult.success(orderId);
    
    }
    

    2.4.5 编辑OrderService

    package com.jt.service;
    
    import com.alibaba.dubbo.config.annotation.Service;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.jt.mapper.OrderItemMapper;
    import com.jt.mapper.OrderMapper;
    import com.jt.mapper.OrderShippingMapper;
    import com.jt.pojo.Order;
    import com.jt.pojo.OrderItem;
    import com.jt.pojo.OrderShipping;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.transaction.annotation.Transactional;
    
    import java.util.List;
    
    @Service
    public class OrderServiceImpl implements  DubboOrderService{
        @Autowired
        private OrderMapper orderMapper;
        @Autowired
        private OrderItemMapper orderItemMapper;
        @Autowired
        private OrderShippingMapper orderShippingMapper;
    
        @Transactional //事务控制
        @Override
        public String saveOrder(Order order) {
            //orderId 由登录用户id和时间戳构成
            String orderId = ""+order.getUserId()+System.currentTimeMillis();
            //完成订单的入库操作
            order.setOrderId(orderId).setStatus(1);
            orderMapper.insert(order);
    
            //完成订单商品入库
            List<OrderItem> orderItems = order.getOrderItems();
    //        for (OrderItem orderItem : orderItems) {
    //            orderItem.setOrderId(orderId);
    //            orderItemMapper.insert(orderItem);
    //
    //        }
           for (OrderItem orderItem : orderItems) {
                orderItem.setOrderId(orderId);
            }
            System.out.println(orderItems);
            orderItemMapper.insertOrderItem(orderItems);
            System.out.println("订单商品入库成功");
    
            //完成订单物流入库
            OrderShipping orderShipping = order.getOrderShipping();
            orderShipping.setOrderId(orderId);
            orderShippingMapper.insert(orderShipping);
            System.out.println("订单物流入库成功");
            return orderId;
        }
    }
    

    2.4.6 OrderItemMapper.xml文件编写

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="com.jt.mapper.OrderItemMapper" >
        <insert id="insertOrderItem">
                insert into tb_order_item values
                <foreach collection="list" item="orderItem" separator="," index="i">
                    (
                        #{orderItem.itemId},
                        #{orderItem.orderId},
                        #{orderItem.num},
                        #{orderItem.title},
                        #{orderItem.price},
                        #{orderItem.totalFee},
                        #{orderItem.picPath},
                        now(),
                        now()
                    )
                </foreach>
        </insert>
    </mapper>
    

    2.5 完成订单查询

    2.5.1 业务分析

    说明:根据orderId查询订单数据.,之后在success页面中展现数据
    在这里插入图片描述

    2.5.2 编辑OrderController

    /**
         *  实现订单的查询 更具orderId
         *  url请求地址http://www.jt.com/order/success.html?id=71598258270221
         *  参数是 id
         *  返回值 success页面
         *  页面参数 ${order.orderId}
         */
        @RequestMapping("/success")
        public String  findOrderById(String id,Model model){
            Order order = dubboOrderService.findOrderById(id);
            model.addAttribute("order",order);
    
            return "success";
        }
    
    

    2.5.3 编辑OrderService

    //查询订单
    @Override
    public Order findOrderById(String id) {
        //查询订单信息
        Order order = orderMapper.selectById(id);
        //查询订单商品
        QueryWrapper<OrderItem> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("item_id",id);
        List<OrderItem> orderItems = orderItemMapper.selectList(queryWrapper);
        //查询订单物流
        OrderShipping orderShipping = orderShippingMapper.selectById(id);
        //封装order
        order.setOrderItems(orderItems).setOrderShipping(orderShipping);
        return order;
    }
    

    2.6 订单超时实现状态修改

    2.6.1业务说明

    说明:当订单入库之后,如果30分钟用户没有完成付款操作,则将订单的状态信息由1未付款改为6交易关闭.
    如何实现: 单独开启一个线程,每隔1分钟查询一次是否有超时订单.

    2.6.2Quartz框架说明

    Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标准的Java组件或 EJBs。Quartz的最新版本为Quartz 2.3.2。

    在这里插入图片描述
    组件说明:
    1.Job 用户自定义的任务.
    2.JobDetail 将用户封装之后的结果.
    3.调度器 负责任务的协调服务.
    4.触发器 当接收调度器的指令后,开启线程执行任务.

    2.6.3 引入jar包文件

    <!--添加Quartz的支持 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-quartz</artifactId>
    </dependency>
    

    2.6.4 关于配置类说明

    package com.jt.conf;
    
    import com.jt.quartz.OrderQuartz;
    import org.quartz.CronScheduleBuilder;
    import org.quartz.JobBuilder;
    import org.quartz.JobDetail;
    import org.quartz.SimpleScheduleBuilder;
    import org.quartz.Trigger;
    import org.quartz.TriggerBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    
    @Configuration //标识为一个配置类
    public class OrderQuartzConfig {
    	
    	//定义任务详情
    	@Bean
    	public JobDetail orderjobDetail() {
    		//指定job的名称和持久化保存任务
    		return JobBuilder
    				.newJob(OrderQuartz.class)//添加自己的任务
    				.withIdentity("orderQuartz")//定义任务名称
    				.storeDurably()
    				.build();
    	}
    	//定义触发器
    	@Bean
    	public Trigger orderTrigger() {
    		/*SimpleScheduleBuilder builder = SimpleScheduleBuilder.simpleSchedule()
    				.withIntervalInMinutes(1)	//定义时间周期
    				.repeatForever();*/
    		//创建一个调度器,之后指定多久执行一次
    		CronScheduleBuilder scheduleBuilder 
    			= CronScheduleBuilder.cronSchedule("0 0/1 * * * ?");
    		return TriggerBuilder
    				.newTrigger()
    				.forJob(orderjobDetail())//执行什么任务
    				.withIdentity("orderQuartz")//任务名称
    				.withSchedule(scheduleBuilder).build();
    	}
    }
    

    说明:关于时间表达式的计算可以点击这里

    2.6.5 执行定时任务

    package com.jt.quartz;
    
    import java.util.Calendar;
    import java.util.Date;
    
    import com.jt.mapper.OrderMapper;
    import com.jt.pojo.Order;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.scheduling.quartz.QuartzJobBean;
    import org.springframework.stereotype.Component;
    import org.springframework.transaction.annotation.Transactional;
    
    import com.alibaba.dubbo.config.annotation.Reference;
    import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
    
    //准备订单定时任务
    @Component
    public class OrderQuartz extends QuartzJobBean{
    
    	@Autowired
    	private OrderMapper orderMapper;
    
    	/**当用户订单提交30分钟后,如果还没有支付.则交易关闭
    	 * 现在时间 - 订单创建时间 > 30分钟  则超时
    	 * new date - 30 分钟 > 订单创建时间
    	 */
    	@Override
    	@Transactional
    	protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
    		//设定30分钟超时
    		Calendar calendar = Calendar.getInstance();
    		calendar.add(Calendar.MINUTE, -30);
    		Date date = calendar.getTime();
    		Order order = new Order();
    		order.setStatus(6);
    		order.setUpdated(new Date());
    		UpdateWrapper<Order> updateWrapper = new UpdateWrapper<>();
    		updateWrapper.eq("status", "1").lt("created",date);
    		orderMapper.update(order, updateWrapper);
    		System.out.println("定时任务执行");
    	}
    }
    
  • 相关阅读:
    监听 view 初始化时
    动画 帧动画
    Android Studio 修改jar包中的.class代码
    ScrollView 滚动条
    SpannableString 设置文字中的颜色 链接
    onActivityResult 解耦 不需要一层一层的写
    滚动 Scroller OverScroller
    startActivity 新开一个Activity
    Fragment java.lang.IllegalStateException 生命周期
    jenkins 基于docker部署springboot项目详细步骤
  • 原文地址:https://www.cnblogs.com/liqbk/p/13556508.html
Copyright © 2020-2023  润新知