B079-项目实战--支付模块 定时任务 项目总结

news2024/9/20 20:38:09

目录

      • 概述
      • 示例
        • jar包
        • 配置类
        • 任务详情
      • 项目应用
        • 封装的工具类QuartzUtils
        • 封装IQuartzSrvice和QuartzServiceImpl
        • 封装参数QuartzJobInfo
        • 编写任务逻辑MainJob
        • 调用第三方支付前添加定时任务
        • 异步回调后移除定时任务
      • 订单支付整体流程

概述

优势:Tmer不支持持久化,重启需要重新安排,Quartz可以持久化,满足大部分需要
缺点:高并发情况下,大量定时任务存在会影响性能。

jvm默认大小500m,定时任务对象太多会内存溢出宕机,该方案只能在1000并发以下比较适合。正常来说我们就满足,只有秒杀,抢单等。。。
高并发情况下要换用消息队列。

原理图
在这里插入图片描述

示例

jar包

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

配置类

添加定时任务的配置类 - 交给spring容器管理就自动会跑起来

@Configuration
public class QuartzConfig {
   @Bean
    public JobDetail newJob(){
        return JobBuilder.newJob(PrintTimeJob.class)//PrintTimeJob我们的业务类
                .withIdentity("9527")//可以给该JobDetail起一个id
                //每个JobDetail内都有一个Map,包含了关联到这个Job的数据,在Job类中可以通过context获取
                .usingJobData("msg", "Hello Quartz")//关联键值对
                .storeDurably()//即使没有Trigger关联时,也不需要删除该JobDetail
                .build();
    }
    @Bean
    public Trigger printTimeJobTrigger() {
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/1 * * * * ? ");
        return TriggerBuilder.newTrigger()
                .forJob(newJob())//关联上述的JobDetail
                .withIdentity("quartzTaskService")//给Trigger起个名字
                .withSchedule(cronScheduleBuilder)
                .build();
    }
}

任务详情

/**
 * 定时任务业务处理类,我们继承QuartzJobBean
 * 重写executeInternal方法来实现具体的定时业务逻辑
 */
public class PrintTimeJob extends QuartzJobBean {

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        //获取JobDetail中关联的数据
        String msg = (String) context.getJobDetail().getJobDataMap().get("msg");
        System.out.println("current time :"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "---" + msg);

    }
}

项目应用

封装的工具类QuartzUtils

import org.quartz.*;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

/**
 * Quartz调度管理器
 */
public class QuartzUtils {
   private static String JOB_GROUP_NAME = "JOB_GROUP_SYSTEM";
   private static String TRIGGER_GROUP_NAME = "TRIGGER_GROUP_SYSTEM";

   /**
    * @Description: 添加一个定时任务,使用默认的任务组名,触发器名,触发器组名
    * @param sched 调度器
    * @param jobName 任务名
    * @param cls 任务
    * @param params 任务参数
    * @param time 时间设置,参考quartz说明文档
    * @Title: QuartzManager.java
    */
   public static void addJob(Scheduler sched, String jobName, @SuppressWarnings("rawtypes") Class cls, Object params,
                             String time) {
      try {
         JobKey jobKey = new JobKey(jobName, JOB_GROUP_NAME);// 任务名,任务组,任务执行类
         @SuppressWarnings("unchecked")

         JobDataMap jobDataMap = new JobDataMap();
         jobDataMap.put("params", params);
         JobDetail jobDetail = newJob(cls).withIdentity(jobKey).setJobData(jobDataMap).build();
         TriggerKey triggerKey = new TriggerKey(jobName, TRIGGER_GROUP_NAME);// 触发器
         Trigger trigger = newTrigger().withIdentity(triggerKey).withSchedule(cronSchedule(time)).build();// 触发器时间设定
         sched.scheduleJob(jobDetail, trigger);
         if (!sched.isShutdown()) {
            sched.start();// 启动
         }
      } catch (Exception e) {
         throw new RuntimeException(e);
      }
   }

   /**
    * @Description: 添加一个定时任务
    * @param sched 调度器
    * @param jobName 任务名
    * @param jobGroupName 任务组名
    * @param triggerName 触发器名
    * @param triggerGroupName 触发器组名
    * @param jobClass 任务
    * @param params 任务参数
    * @param time 时间设置,参考quartz说明文档
    * @Title: QuartzManager.java
    */
   public static void addJob(Scheduler sched, String jobName, String jobGroupName, String triggerName,
                             String triggerGroupName, @SuppressWarnings("rawtypes") Class jobClass,  Object params, String time) {
      try {
         JobKey jobKey = new JobKey(jobName, jobGroupName);
         JobDataMap jobDataMap = new JobDataMap();
         jobDataMap.put("params", params);
         @SuppressWarnings("unchecked")
         JobDetail jobDetail = newJob(jobClass).withIdentity(jobKey).setJobData(jobDataMap).build();
         // 触发器
         TriggerKey triggerKey = new TriggerKey(triggerName, triggerGroupName);
         Trigger trigger = newTrigger().withIdentity(triggerKey).withSchedule(cronSchedule(time)).build();
         sched.scheduleJob(jobDetail, trigger);
      } catch (Exception e) {
         throw new RuntimeException(e);
      }
   }

   /**
    * @Description: 修改一个任务的触发时间(使用默认的任务组名,触发器名,触发器组名)
    * @param sched 调度器
    * @param jobName
    * @param time
    * @Title: QuartzManager.java
    */
   @SuppressWarnings("rawtypes")
   public static void modifyJobTime(Scheduler sched, String jobName, String time) {
      try {
         TriggerKey triggerKey = new TriggerKey(jobName, TRIGGER_GROUP_NAME);
         CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
         if (trigger == null) {
            return;
         }
         String oldTime = trigger.getCronExpression();
         if (!oldTime.equalsIgnoreCase(time)) {
            JobKey jobKey = new JobKey(jobName, JOB_GROUP_NAME);
            JobDetail jobDetail = sched.getJobDetail(jobKey);
            Class objJobClass = jobDetail.getJobClass();
            Object params = jobDetail.getJobDataMap().get("params");
            removeJob(sched, jobName);
            System.out.println("修改任务:" + jobName);
            addJob(sched, jobName, objJobClass, params,time);
         }
      } catch (Exception e) {
         throw new RuntimeException(e);
      }
   }

   /**
    * @Description: 修改一个任务的触发时间
    * @param sched 调度器
    * @param sched 调度器
    * @param triggerName
    * @param triggerGroupName
    * @param time
    * @Title: QuartzManager.java
    */
   public static void modifyJobTime(Scheduler sched, String triggerName, String triggerGroupName, String time) {
      try {
         TriggerKey triggerKey = new TriggerKey(triggerName, triggerGroupName);
         CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
         if (trigger == null) {
            return;
         }
         String oldTime = trigger.getCronExpression();
         if (!oldTime.equalsIgnoreCase(time)) {
            // 修改时间
            trigger.getTriggerBuilder().withSchedule(cronSchedule(time));
            // 重启触发器
            sched.resumeTrigger(triggerKey);
         }
      } catch (Exception e) {
         throw new RuntimeException(e);
      }
   }

   /**
    * @Description: 移除一个任务(使用默认的任务组名,触发器名,触发器组名)
    * @param sched 调度器
    * @param jobName
    * @Title: QuartzManager.java
    */
   public static void removeJob(Scheduler sched, String jobName) {
      try {
         TriggerKey triggerKey = new TriggerKey(jobName, TRIGGER_GROUP_NAME);
         sched.pauseTrigger(triggerKey);// 停止触发器
         sched.unscheduleJob(triggerKey);// 移除触发器
         JobKey jobKey = new JobKey(jobName, JOB_GROUP_NAME);
         boolean b = sched.deleteJob(jobKey);// 删除任务
         System.out.println(b);
      } catch (Exception e) {
         throw new RuntimeException(e);
      }
   }

   /**
    * @Description: 移除一个任务
    * @param sched 调度器
    * @param jobName
    * @param jobGroupName
    * @param triggerName
    * @param triggerGroupName
    * @Title: QuartzManager.java
    */
   public static void removeJob(Scheduler sched, String jobName, String jobGroupName, String triggerName,
                                String triggerGroupName) {
      try {
         TriggerKey triggerKey = new TriggerKey(triggerName, triggerGroupName);
         sched.pauseTrigger(triggerKey);// 停止触发器
         sched.unscheduleJob(triggerKey);// 移除触发器
         JobKey jobKey = new JobKey(jobName, jobGroupName);
         sched.deleteJob(jobKey);// 删除任务
      } catch (Exception e) {
         throw new RuntimeException(e);
      }
   }

   /**
    * @Description:启动所有定时任务
    * @param sched  调度器
    * @Title: QuartzManager.java
    */
   public static void startJobs(Scheduler sched) {
      try {
         sched.start();
      } catch (Exception e) {
         throw new RuntimeException(e);
      }
   }

   /**
    * @Description:关闭所有定时任务
    * @param sched 调度器
    */
   public static void shutdownJobs(Scheduler sched) {
      try {
         if (!sched.isShutdown()) {
            sched.shutdown();
         }
      } catch (Exception e) {
         throw new RuntimeException(e);
      }
   }
}

封装IQuartzSrvice和QuartzServiceImpl

IQuartzService

public interface IQuartzService {

    //1.添加定时任务
    void addJob(QuartzJobInfo quartzJobInfo);

    // 2. 移出定时任务
    void removeJob(String jobName);

}

QuartzServiceImpl

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;

@Service
public class QuartzServiceImpl implements IQuartzService {

    @Autowired
    private SchedulerFactoryBean schedulerFactory;

    /*
     * @param scheduler
     * @param jobName
     * @param cls
     * @param params
     * @param time 时间表达式 定时任务执行的时间   已知 执行的时间  Date--->0/1 * * * * ?
     */
    @Override
    public void addJob(QuartzJobInfo quartzJobInfo) {
        /*  Scheduler sched, String jobName, @SuppressWarnings("rawtypes") Class cls, Object params,String time  */
        try {
            QuartzUtils.addJob(schedulerFactory.getScheduler(),quartzJobInfo.getJobName() , MainJob.class,quartzJobInfo.getParams() , quartzJobInfo.getCronj());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void removeJob(String orderSn) {
       QuartzUtils.removeJob(schedulerFactory.getScheduler(),orderSn);
    }
}

封装参数QuartzJobInfo

import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;

@Data
public class QuartzJobInfo implements Serializable {
    private byte type;
    private String jobName;
    private Map<String, Object> params;
    private String cronj;
    private Date fireDate;

    public void setFireDate(Date fireDate) {
        this.fireDate = fireDate;
        String[] cronArr = new String[7];
        for (int i = 0; i < cronArr.length; i++) {
            cronArr[i] = "";
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(fireDate);
        int second = calendar.get(Calendar.SECOND);
        int minute = calendar.get(Calendar.MINUTE);
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        int day = calendar.get(Calendar.DAY_OF_MONTH);
        int month = calendar.get(Calendar.MONTH) + 1;
        int year = calendar.get(Calendar.YEAR);
        cronArr[0] = second + "";
        cronArr[1] = minute + "";
        cronArr[2] = hour + "";
        cronArr[3] = day + "";
        cronArr[4] = month + "";
        cronArr[5] = "?";
        cronArr[6] = year + "";
        String cron = StringUtils.join(cronArr," ").trim();
        this.setCronj(cron);
    }
}

编写任务逻辑MainJob

import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.Map;

@Component
public class MainJob implements Job {

    @Autowired
    private IPayBillService payBillService;
    @Autowired
    private IAdoptOrderService adoptOrderService;
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        //获取定时器里面的数据
        JobDataMap jobDataMap = context.getMergedJobDataMap();
        Map<String,Object> params = (Map<String, Object>) jobDataMap.get("params");
        //获取定时任务的订单号
        String orderSn = params.get("orderSn").toString();

        //执行 修改订单状态的业务逻辑
        //1.改订单的状态
        PayBill payBill = payBillService.loadByUnionPaySn(orderSn);
        payBill.setState(-1);
        payBill.setUpdateTime(new Date());
        payBillService.update(payBill);

        if(PayConstants.BUSINESS_TYPE_ADOPT.equals(payBill.getBusinessType())){//领养订单
            Long orderId = payBill.getBusinessKey();
            AdoptOrder order = adoptOrderService.getById(orderId);
            order.setState(-1);
            adoptOrderService.update(order);
        }
    }
}

调用第三方支付前添加定时任务

AdoptOrderServiceImpl

@Service
public class AdoptOrderServiceImpl extends BaseServiceImpl<AdoptOrder> implements IAdoptOrderService {
    @Autowired
    private PetMapper petMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private AdoptOrderMapper adoptOrderMapper;
    @Autowired
    private UserAddressMapper userAddressMapper;
    @Autowired
    private OrderAddressMapper orderAddressMapper;
    @Autowired
    private EmployeeMapper employeeMapper;
    @Autowired
    private PayBillMapper payBillMapper;
    @Autowired
    private IPayBillService payBillService;
    @Autowired
    private IQuartzService quartzService;

    /**
     * 领养订单结算
     */
    @Override
    @Transactional
    public String submit(Map<String, Object> params, Logininfo loginIn) {
        Long petId = Long.valueOf(params.get("pet_id").toString());
        Long addressId = Long.valueOf(params.get("address_id").toString());//收货地址:t_user_address的id
        Integer payMethod = Integer.valueOf(params.get("pay_method").toString());//1支付宝 2微信  3银联 0余额
        Integer serviceMethod = Integer.valueOf(params.get("service_method").toString());//送货方式

        //1.修改状态  下架
        Pet pet = petMapper.loadById(petId);
        pet.setState(0);
        pet.setOffsaletime(new Date());
        //2.绑定用户
        User user = userMapper.loadByloingInfoId(loginIn.getId());
        pet.setUser(user);
        pet.setUser_id(user.getId());
        pet.setShop_id(pet.getShop().getId());
        petMapper.update(pet);
        //3.生成订单  一次性
        AdoptOrder order = initAdoptOrder(pet, user);
        //骚操作:为了后边操作支付单,不用再来修改订单,先生成统一的支付单号
        String unionPaySn = CodeGenerateUtils.generateUnionPaySn();
        order.setPaySn(unionPaySn);

        adoptOrderMapper.save(order);

        // 3.1 生成订单地址
        UserAddress userAddress = userAddressMapper.loadById(addressId);
        OrderAddress orderAddress = userAddress2OrderAddress(order, userAddress);
        orderAddressMapper.save(orderAddress);

        // 4.支付单
        PayBill payBill = initPayBill(payMethod, pet, user, order);
        payBillMapper.save(payBill);

        // 5.针对支付单添加定时任务
        QuartzJobInfo info = new QuartzJobInfo();
        info.setJobName(order.getPaySn());//定时任务的唯一标识
        Map<String, Object> map = new HashMap<>();
        map.put("orderSn", payBill.getUnionPaySn());
        // 定时任务 需要的 数据
        info.setParams(map);
        info.setFireDate(payBill.getLastPayTime());//最后的支付时间,定时任务的执行时间
        quartzService.addJob(info);

        //调用统一支付接口(老杨定义的)
        return payBillService.pay(payBill);
    }

    private PayBill initPayBill(Integer payMethod, Pet pet, User user, AdoptOrder order) {
        PayBill payBill = new PayBill();
        payBill.setDigest(order.getDigest()+"支付单");
        payBill.setMoney(order.getPrice());
        //重点:支付唯一表示
        payBill.setUnionPaySn(order.getPaySn());
        payBill.setLastPayTime(new Date(System.currentTimeMillis() + 15*60*1000));
        payBill.setPayChannel(Long.valueOf(payMethod));//0 余额 1 支付宝 2 微信 3 银联
        payBill.setBusinessType(PayConstants.BUSINESS_TYPE_ADOPT);
        payBill.setBusinessKey(order.getId());
        payBill.setUser_id(user.getId());
        payBill.setShop_id(pet.getShop().getId());
        payBill.setNickName(user.getUsername());
        return payBill;
    }

    @Override
    public PageList<AdoptOrder> queryAdmin(AdoptOrderQuery query, Long loginInfoId) {
        //1.通过loginInfoID查询出Employee
        Employee employee = employeeMapper.loadByLoginInfoId(loginInfoId);
        //2.如果employee中的shopID不为null,就是店铺。否则就是平台员工
        if (employee.getShop_id() != null) {
            query.setShopId(employee.getShop_id());
        }
        return super.queryPage(query);
    }

    @Override
    public PageList<AdoptOrder> queryUser(AdoptOrderQuery query, Long loginInfoId) {
        User user = userMapper.loadByloingInfoId(loginInfoId);
        query.setUserId(user.getId());
        return super.queryPage(query);
    }

    private OrderAddress userAddress2OrderAddress(AdoptOrder order, UserAddress userAddress) {
        OrderAddress orderAddress = new OrderAddress();
        BeanUtils.copyProperties(userAddress, orderAddress);
        orderAddress.setId(null);
        orderAddress.setOrder_id(order.getId());
        orderAddress.setOrderSn(order.getOrderSn());
        return orderAddress;
    }

    /**
     * alt  + shift + m
     *
     * @param petId
     * @param pet
     * @param user
     * @return
     */
    private AdoptOrder initAdoptOrder(Pet pet, User user) {

        AdoptOrder order = new AdoptOrder();
        order.setDigest("【摘要】" + pet.getName());
        order.setPrice(pet.getSaleprice());
        order.setOrderSn(CodeGenerateUtils.generateOrderSn(user.getId()));
        order.setLastConfirmTime(new Date(System.currentTimeMillis() + PayConstants.LAST_TIME));//最后确认时间
        order.setPet_id(pet.getId());
        order.setUser_id(user.getId());
        order.setShop_id(pet.getShop().getId());
        return order;
    }
}

异步回调后移除定时任务

AlipayController

@RestController
public class AlipayController {

    @Autowired
    private IPayBillService payBillService;
    @Autowired
    private IAlipayInfoService alipayInfoService;
    @Autowired
    private IAdoptOrderService adoptOrderService;
    @Autowired
    private IQuartzService quartzService;

    @PostMapping("/notify")
    public void notify(HttpServletRequest request){
        System.out.println("支付宝异步回调!");
        //获取支付宝POST过来反馈信息
        try {
            Map<String,String> params = new HashMap<String,String>();
            Map<String,String[]> requestParams = request.getParameterMap();
            for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
                String name = (String) iter.next();
                String[] values = (String[]) requestParams.get(name);
                String valueStr = "";
                for (int i = 0; i < values.length; i++) {
                    valueStr = (i == values.length - 1) ? valueStr + values[i]
                            : valueStr + values[i] + ",";
                }
                valueStr = new String(valueStr);
                params.put(name, valueStr);
            }

            String unionPaySn = params.get("out_trade_no");
            PayBill payBill = payBillService.loadByUnionPaySn(unionPaySn);
            if(payBill != null){
                AlipayInfo info = alipayInfoService.getByShopId(payBill.getShop_id());
                boolean signVerified = AlipaySignature.rsaCheckV1(params,
                        info.getAlipay_public_key(),
                        AlipayConfig.charset,
                        AlipayConfig.sign_type); //调用SDK验证签名

                if(signVerified) {//验证成功
                    //商户订单号
                    String out_trade_no = unionPaySn;
                    //支付宝交易号
                    String trade_no = request.getParameter("trade_no");
                    //交易状态
                    String trade_status = request.getParameter("trade_status");
                    if(trade_status.equals("TRADE_FINISHED")){
                        //用户确认
                    }else if (trade_status.equals("TRADE_SUCCESS")){
                        //1. 改支付单状态
                        payBill.setState(1);
                        payBill.setUpdateTime(new Date());
                        payBillService.update(payBill);
                        String businessType = payBill.getBusinessType();
                        //2.再修改对应(领养)的订单状态  businessType   businessKey 订单
                        if(PayConstants.BUSINESS_TYPE_ADOPT.equals(businessType)){//领养订单
                            Long orderId = payBill.getBusinessKey();
                            AdoptOrder order = adoptOrderService.getById(orderId);
                            order.setState(1);
                            adoptOrderService.update(order);
                        }
                        //移除针对当前订单的定时任务
                        quartzService.removeJob(out_trade_no);
                    }
                }else {//验证失败
                    System.out.println("老宋,不要搞事");
                    //调试用,写文本函数记录程序运行情况是否正常
                    //String sWord = AlipaySignature.getSignCheckContentV1(params);
                    //AlipayConfig.logResult(sWord);
                }
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

订单支付整体流程

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/821009.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

亚马逊水基灭火器UL8测试报告ISO17025实验室办理

在跨境电商平台上销售的境外电商&#xff0c;在美国市场中需要提供相关的安全规范报告。其中&#xff0c;美国相关部门要求&#xff0c;如果商家未能提交UL&#xff08;Underwriters Laboratories&#xff09;标准的检测报告&#xff0c;将会被责令停止销售。而为了在亚马逊、T…

【论文精读】用于多文档摘要生成的层次Transformer方法

前言 论文分享 来自2019ACL的多文档摘要生成方法论文&#xff0c;作者来自英国爱丁堡大学&#xff0c;引用数310 Hierarchical Transformers for Multi-Document Summarization 代码地址hiersumm 多文档摘要抽取的难点在于没有合适的数据集&#xff0c;同时过长的文档文本也导…

Makefile模板和工程模板(消息队列和共享内存)的使用

一、 Makefile模板 #指定生成的文件名 OJB_OUT test#指定每一个c文件对应的.o文件 OBJS a.o b.o main.o#指定编译器 CC gcc#指定需要的库 ULDFLAGS ########################################### #以下的内容不需要修改 ########################################### all:…

行业追踪,2023-08-01

自动复盘 2023-08-01 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

leetcode-143-重排链表

题意描述&#xff1a; 给定一个单链表 L 的头节点 head &#xff0c;单链表 L 表示为&#xff1a; L0 → L1 → … → Ln - 1 → Ln 请将其重新排列后变为&#xff1a; L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … 不能只是单纯的改变节点内部的值&#xff0c;而是需要…

cmake+pybind11打包c++库成python wheel安装包

目录 写在前面准备1、pybind11获取源码编译安装 2、conda demo官方源码修改CMakeLists.txt编译生成安装测试 参考完 写在前面 1、本文内容 有时候我们需要用c代码&#xff0c;供python调用&#xff0c;本文提供将c库封装成python接口的方法&#xff0c;并将库打包成可通过pip安…

Apikit 自学日记:API 异常监控-创建 API 监控

如何在apikit中&#xff0c;创建 API 监控呢&#xff1f; 创建并开启监控API 一、手动创建监控API Eolink API 网络监控平台支持从 Eolink API Management&#xff08;API管理产品&#xff09;中导入API信息&#xff0c;或者手动创建监控API。 进入API监控页面&#xff0c;点击…

23款奔驰S450 4MATIC升级原厂流星雨智能数字大灯,让智能照亮您前行的路

凭借智能数字大灯 (DIGITAL LIGHT)&#xff0c;您可体验根据其他道路使用者和周围环境进行优化调节的理想照明条件。这款包含130万像素模块大灯&#xff0c;进一步扩展了几何多光束 LED 大灯的功能。其高分辨率的照明可有针对性地点亮各个区域。解锁车辆时&#xff0c;大灯将通…

快速制作美容行业预约小程序

随着科技的不断进步&#xff0c;移动互联网的快速发展&#xff0c;小程序成为了很多行业迅速发展的利器。对于美容行业来说&#xff0c;一款美容预约小程序不仅可以方便用户进行预约&#xff0c;还可以提升美容店铺的服务质量和管理效率。下面&#xff0c;我们来介绍一下如何快…

23 设计模式(详细介绍附DEMO)

设计模式在Java中的应用与实现 &#x1f680;&#x1f680;&#x1f680;1.创建型模式1. 工厂方法模式&#xff08;Factory Pattern&#xff09;2.抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;3. 单例模式&#xff08;Singleton Pattern&#xff09;4.原型模…

rfid资产盘点管理系统软件

很多企业开始规划固定资产的总结&#xff0c;或者现在开始总结资产。面对众多不同种类的固定资产&#xff0c;总结已经成为一项工程量大、耗时长的任务。采用轻松的RFID固定资产管理系统后&#xff0c;可以大大提高这种总结工作的效率&#xff0c;获得比过去更清晰的资产清单和…

三菱plcCCLINK转profinet与西门子PLC通讯案例分析

用三菱PLC的控制系统需要和西门子的PLC控制系统交互数据&#xff0c;捷米JM-PN-CCLK 是自主研发的一款 PROFINET 从站功能的通讯网关。该产品主要功能是将各种 CCLINK 总线和 PROFINET 网络连接起来。 捷米JM-PN-CCLK总线中做为从站使用&#xff0c;连接到 CCLINK 总线中做为…

【C++】基于多设计模式下的同步异步日志系统

✍作者&#xff1a;阿润021 &#x1f4d6;专栏&#xff1a;C 文章目录 一、项目介绍二、项目实现准备工作1.日志系统技术实现策略2.相关技术知识补充2.1 不定参函数设计2.2 设计模式 三、日志项目框架设计1.模块划分2.各模块关系图 四、详细代码实现1.实用工具类设计2.日志等级…

StampedLock使用及源码分析:号称比读写锁还要快的锁

文章目录 一、StampedLock锁概述1、StampedLock锁简介2、ReentrantReadWriteLock回顾3、ReentrantReadWriteLock导致锁饥饿问题4、锁饥饿问题的缓解5、StampedLock与ReentrantReadWriteLock的对比6、StampedLock特点7、StampedLock的缺点 二、StampedLock的使用1、StampedLock的…

基于PHP校园疫情防控信息管理系统-计算机毕设 附源码12057

PHP校园疫情防控信息管理系统 摘 要 如今计算机行业的发展极为快速&#xff0c;搭载于计算机软件运行的数据库管理系统在各行各业得到了广泛的运用&#xff0c;其在数据管理方面具有的准确性和高效性为大中小企业的日常运营提供了巨大的帮助。自从2020年新冠疫情爆发以来&…

ArduPilot H743 Dual BMI270 Mark4 四轴DIY简单功能验证

ArduPilot H743 Dual BMI270 Mark4 四轴DIY简单功能验证 1. 源由2. 梳理2.1 基本配置2.2 滤波配置2.3 FPV-VTX配置2.4 FPV操控2.5 自适应PID调参2.6 电传配置 3. 视频3.1 FPV操控性3.2 路点巡航3.3 救援模式 4. 总结5. 参考资料6. 补充说明--问题集中回答 1. 源由 基于Mark4机…

易上手的数据报表工具有哪些?奥威BI零编程

易上手的数据报表功能有哪些&#xff1f;实际上&#xff0c;国产的BI报表工具都算得上是易上手的&#xff0c;因为它们大多都是低代码的BI报表工具&#xff0c;只需掌握基础SQL即可。但奥威BI报表工具却是零编程做大数据分析的BI报表工具。要说易上手&#xff0c;奥威BI报表工具…

Spark-统一内存模型

总结&#xff1a; Spark的内存模型分为4部分&#xff0c;分别是存储内存&#xff0c;计算内存&#xff0c;其他内存&#xff0c;预留内存&#xff1b; 其中存储内存和计算内存可以动态占用&#xff0c;当己方内存不足对方空余则可占用对方的内存&#xff0c;计算内存被存储内…

Attention机制竟有bug,Softmax是罪魁祸首,影响所有Transformer

大模型开发者&#xff0c;你们错了&#xff01; 「我发现注意力公式里有个 bug&#xff0c;八年了都没有人发现。所有 Transformer 模型包括 GPT、LLaMA 都受到了影响。」 昨天&#xff0c;一位名叫 Evan Miller 的统计工程师的话在 AI 领域掀起了轩然大波。 我们知道&#x…

解决单节点es索引yellow

现象 单节点的es&#xff0c;自动创建索引后&#xff0c;默认副本个数为1&#xff0c;索引状态为yellow 临时解决 修改副本个数为0 永久解决 方法1、修改elasticsearch.yml文件&#xff0c;添加配置并重启es number_of_replicas&#xff1a;副本分片数&#xff0c;默认…