Day72(9)-F:\硕士阶段\Java\课程资料\1、黑马程序员Java项目《苍穹外卖》企业级开发实战\sky-take-out

苍穹外卖

SpringTask

image-20251230143423628

image-20251230143559373

cron

image-20251230145732765

image-20251230145740397

https://cron.qqe2.com/

image-20251230150626048

package com.sky.task;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * 自定义定时任务类
 */

@Component
@Slf4j
public class MyTask {

    /**
     * 定时任务,每隔五秒触发一次
     */
    @Scheduled(cron = "0/5 * * * * ? ")
    public void executeTask(){
        log.info("任务开始执行:{}",new Date());
    }
}

订单定时处理

image-20251230151453195

image-20251230151459410

image-20251230151603734

image-20251230151724525

技术栈:

  1. 轮询
1.轮询
package com.sky.task;

import com.sky.entity.Orders;
import com.sky.mapper.OrderMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 定时任务类,定时处理订单状态
 */
@Component
@Slf4j
public class OrderTask {
    @Autowired
    private OrderMapper orderMapper;


    /**
     * 处理超时订单的方法
     */
    //@Scheduled(cron = "0/5 * * * * ? ")
    @Scheduled(cron = "0 * * * * *")
    public void processTimeoutOrder(){

        log.info("定时处理超时订单:{}", LocalDateTime.now());

        LocalDateTime time = LocalDateTime.now().plusMinutes(-15);
        //select * from orders where status = ? and order_time < (当前时间-15分钟)
        List<Orders> ordersList = orderMapper.getByStatusAndOrderTimeLT(Orders.PENDING_PAYMENT, time);

        if (ordersList!=null&&ordersList.size()>0){
            for (Orders orders : ordersList) {
                orders.setStatus(Orders.CANCELLED);
                orders.setCancelReason("订单超时,自动取消");
                orders.setCancelTime(LocalDateTime.now());
                orderMapper.update(orders);
            }
        }
    }

    /**
     * 处理一直处于派送中状态的订单
     */
    @Scheduled(cron = "0 0 1 * * ?")
    //@Scheduled(cron = "0/10 * * * * ? ")
    public void processDeliveryOrder(){
        log.info("定时处理一直处于派送中的订单:{}",LocalDateTime.now());

        LocalDateTime time = LocalDateTime.now().plusMinutes(-60);
        List<Orders> ordersList = orderMapper.getByStatusAndOrderTimeLT(Orders.DELIVERY_IN_PROGRESS, time);

        if (ordersList!=null&&ordersList.size()>0){
            for (Orders orders : ordersList) {
                orders.setStatus(Orders.COMPLETED);
                orderMapper.update(orders);
            }
        }
    }
}

WebSocket

http是短连接

image-20251230155914950

image-20251230160043171

image-20251230160350352

image-20251230160806771

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
package com.sky.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * WebSocket配置类,用于注册WebSocket的Bean
 */
@Configuration
public class WebSocketConfiguration {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

server类相当于controller

package com.sky.websocket;

import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * WebSocket服务
 */
@Component
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {

    //存放会话对象
    private static Map<String, Session> sessionMap = new HashMap();

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        System.out.println("客户端:" + sid + "建立连接");
        sessionMap.put(sid, session);
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, @PathParam("sid") String sid) {
        System.out.println("收到来自客户端:" + sid + "的信息:" + message);
    }

    /**
     * 连接关闭调用的方法
     *
     * @param sid
     */
    @OnClose
    public void onClose(@PathParam("sid") String sid) {
        System.out.println("连接断开:" + sid);
        sessionMap.remove(sid);
    }

    /**
     * 群发
     *
     * @param message
     */
    public void sendToAllClient(String message) {
        Collection<Session> sessions = sessionMap.values();
        for (Session session : sessions) {
            try {
                //服务器向客户端发送消息
                session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}
package com.sky.task;

import com.sky.websocket.WebSocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Component
public class WebSocketTask {
    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 通过WebSocket每隔5秒向客户端发送消息
     */
    @Scheduled(cron = "0/5 * * * * ?")
    public void sendMessageToClient() {
        webSocketServer.sendToAllClient("这是来自服务端的消息:" + DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now()));
    }
}

来单提醒

image-20251230172516845

image-20251230172912003

技术栈

  1. nginx反向代理配置
  2. 通过webSocket在支付成功后推送过来,在impl中完成这个操作
1.nginx反向代理配置

在nginx的配置类中有

# WebSocket
location /ws/ {
          proxy_pass   http://webservers/ws/;
    proxy_http_version 1.1;
    proxy_read_timeout 3600s;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "$connection_upgrade";
      }
upstream webservers{
  server 127.0.0.1:8080 weight=90 ;
  #server 127.0.0.1:8088 weight=10 ;
}
2.通过webSocket在支付成功后推送过来,在impl中完成这个操作

如果是微信能支付应该是在微信后台回调后端之后发送这个信息

/**
 * 支付成功,修改订单状态
 *
 * @param outTradeNo
 */
public void paySuccess(String outTradeNo) {

    // 根据订单号查询订单
    Orders ordersDB = orderMapper.getByNumber(outTradeNo);

    // 根据订单id更新订单的状态、支付方式、支付状态、结账时间
    Orders orders = Orders.builder()
            .id(ordersDB.getId())
            .status(Orders.TO_BE_CONFIRMED)
            .payStatus(Orders.PAID)
            .checkoutTime(LocalDateTime.now())
            .build();

    orderMapper.update(orders);

    //通过WebSocket向客户端浏览器推送信息 type orderId Content
    Map<Object, Object> map = new HashMap<>();
    map.put("type",1);//1.表示来单提醒  2.表示客户催单
    map.put("orderId",ordersDB.getId());
    map.put("content","订单号:"+outTradeNo);

    String json = JSON.toJSONString(map);

    webSocketServer.sendToAllClient(json);

}

但是我们不能,个体账户无法支付

所以改为在payment就发信息(38-48行)

/**
     * 订单支付
     *
     * @param ordersPaymentDTO
     * @return
     */
    public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception {
        // 当前登录用户id
        Long userId = BaseContext.getCurrentId();
        User user = userMapper.getById(userId);

        //调用微信支付接口,生成预支付交易单
//        JSONObject jsonObject = weChatPayUtil.pay(
//                ordersPaymentDTO.getOrderNumber(), //商户订单号
//                new BigDecimal(0.01), //支付金额,单位 元
//                "苍穹外卖订单", //商品描述
//                user.getOpenid() //微信用户的openid
//        );
//
//        if (jsonObject.getString("code") != null && jsonObject.getString("code").equals("ORDERPAID")) {
//            throw new OrderBusinessException("该订单已支付");
//        }

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", "ORDERPAID");

        OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class);
        //vo.setPackageStr(jsonObject.getString("package"));


        //为替代微信支付成功后的数据库订单状态更新,多定义一个方法进行修改
        Integer OrderPaidStatus = Orders.PAID; //支付状态,已支付
        Integer OrderStatus = Orders.TO_BE_CONFIRMED;  //订单状态,待接单
        //发现没有将支付时间 check_out属性赋值,所以在这里更新
        LocalDateTime check_out_time = LocalDateTime.now();
        orderMapper.updateStatus(OrderStatus, OrderPaidStatus, check_out_time, Long.valueOf(ordersPaymentDTO.getOrderNumber()));

        // 根据订单号查询当前用户的订单
        Orders ordersDB = orderMapper.getByNumber(ordersPaymentDTO.getOrderNumber());
        //通过WebSocket向客户端浏览器推送信息 type orderId Content
        Map<Object, Object> map = new HashMap<>();
        map.put("type",1);//1.表示来单提醒  2.表示客户催单
        map.put("orderId",ordersDB.getId());
        map.put("content","订单号:"+ordersPaymentDTO.getOrderNumber());

        String json = JSON.toJSONString(map);

        webSocketServer.sendToAllClient(json);
        return vo;
    }

客户催单

image-20251230190445116

image-20251230190612444

image-20251230190736012

/**
 * 客户催单
 * @param id
 * @return
 */
@ApiOperation("客户催单")
@GetMapping("/reminder/{id}")
public Result reminder(@PathVariable Long id){
    log.info("客户催单:{}",id);
    orderService.reminder(id);
    return Result.success();
}
/**
 * 客户催单
 * @param id
 */
@Override
public void reminder(Long id) {
    Orders orders = orderMapper.getById(id);
    if (orders==null||orders.getStatus()!=Orders.TO_BE_CONFIRMED){
        throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
    }

    HashMap<Object, Object> map = new HashMap<>();
    map.put("type",2);//1.表示来单提醒  2.表示客户催单
    map.put("orderId",id);
    map.put("content",orders.getNumber());
    String json = JSON.toJSONString(map);

    webSocketServer.sendToAllClient(json);
}
posted @ 2025-12-30 19:37  David大胃  阅读(5)  评论(0)    收藏  举报