接口开发之使用C#插件Quartz.Net定时执行CMD任务工具

C#制作定时任务工具执行CMD命令

  • 概要
  • 准备
  • 知识点
    • 实现原理
    • thinkphp配置
    • winform
    • 执行CMD命令
    • 读取ini配置文件
    • 定时任务Quartz.Net
  • 完整代码
    • Job.cs
    • IniFunc.cs
    • Form1.cs
    • config.ini
    • 简易定时任务工具雏形

概要

  • 很多时候写接口上线后还会遇到很多修改,类似JAVA,C#,delphi制作的接口上线后难以修改,测试也有困难。
  • 为了接口便于制作和修改,采用动态语言编写接口+定时任务基座的处理方法,例如:PHP写的接口内容,使用定时任务工具定时执行,这样即使接口上线后也可以随意修改PHP这种解释性脚本,方便修改和定位错误。
  • 定时任务工具+python也是很好的解决方案
  • 定时任务可以采用JAVA或者C#来构建,目前采用C#构建定时任务桌面工具

准备

  • vs2019+C# winform
  • phpstudy2016+thinkphp3.2.3
  • quartz.net 3.7.2

知识点

实现原理

  • thinkphp启用cmd执行程序
  • C#利用定时任务框架quartz.net去执行CMD命令

thinkphp配置

  • 开发阶段可以使用phpstudy环境,部署阶段采用cmd命令可以不使用网络容器
  • thinkphp开启cli模式:入库文件index.php添加一句就可以了
if(version_compare(PHP_VERSION,'5.3.0','<'))  die('require PHP > 5.3.0 !');
//添加这一句就可以了
define('MODE_NAME', 'cli');
...其他不变
  • 配置后网络容器和CMD都可以执行thinkphp,CMD执行语句:
D:\phpStudy\php\php-7.0.12-nts\php.exe  D:\phpStudy\WWW\tp3\index.php Home/Index/queryAndWrite

说明:绝对路径找到php.exe,去执行thinkphp中的方法
另外,如果不采用自定义基座(定时任务工具),可以使用win自带的计划任务也行,但是计划任务会弹出cmd框,所以在cmd命令旁添加一个vb命令,执行这个vb命令就不会有弹窗了:

Set ws = CreateObject("Wscript.Shell")    
ws.run "cmd /c times.bat",vbhide

在这里插入图片描述

winform

  • 项目结构:
    在这里插入图片描述
    说明:
    引用:类似java的maven包
    Form1.cs:窗口1,其中Form1.Designer.cs是编译器自动生成的布局代码,和Form是分步类,等同一个类分成2个文件
    IniFunc.cs:读取ini配置文件
    Job.cs:具体任务,这里只有一个任务,但是通过不同的触发器传值形成不同任务分身
    Promgram.cs:程序入口

  • 任务类中调用Form1的控件

  1. From1定义为静态类
 		public static Form1 form1;
        public Form1()
        {
            InitializeComponent();
            form1 = this;
        }
  1. 控件设置成public
    在这里插入图片描述

  2. Job通过静态类访问From1控件

var c = Form1.form1.textBox1.Text;
MessageBox.Show(c);

执行CMD命令

//需要引入using System.Diagnostics;
private void cmd(String t)
   {
       var p = new Process();
       p.StartInfo.FileName = "cmd.exe";
       p.StartInfo.RedirectStandardInput = true;
       p.StartInfo.UseShellExecute = false;
       p.StartInfo.CreateNoWindow = true;
       p.Start();
       p.StandardInput.WriteLine(t);
       //p.StandardInput.WriteLine("exit");
       p.StandardInput.Flush();
   }

读取ini配置文件

  1. Debug目录下新建config.ini
[Information]
job1=D:\phpStudy\php\php-7.0.12-nts\php.exe  D:\phpStudy\WWW\tp3\index.php Home/Index/queryAndWrite
job2=D:\phpStudy\php\php-7.0.12-nts\php.exe  D:\phpStudy\WWW\tp3\index.php Home/Index/queryAndWrite2
  1. 定义文件路径,在Form1事件load中选择Form1_Load,然后按钮1点击后获取配置文件内容,job1和job2是两个定时任务,去执行thinkphp中的数据库操作
		private string filename = null;

        private void Form1_Load(object sender, EventArgs e)
        {

            filename = Application.StartupPath + "\\config.ini";
            //MessageBox.Show(filename);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //this.textBox1.Text = "777";
            string job1 = IniFunc.getString("Information", "job1", null, filename);
            string job2 = IniFunc.getString("Information", "job2", null, filename);
            textBox1.Text = job1;
            textBox2.Text = job2;
            //Task(job1,job2);
        }

定时任务Quartz.Net

  • 安装:
  1. 右键项目,点击管理NuGet
  2. 浏览中搜索quartz,点击安装
  3. 安装成功后在项目引用中会有quartz.dll
  • 构建定时任务大概分为4步:
  1. 构建scheduler(任务管理器)并开启
  2. 创建job,添加job
  3. 构建触发器
  4. scheduler中添加job

完整代码

Job.cs

using Quartz;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public class Job : IJob
    {
        //public static readonly JobKey Key = new JobKey("customer-process", "group");//这里是定义job唯一key
        public async Task Execute(IJobExecutionContext context)
        {
            var customerId = context.MergedJobDataMap.GetString("CustomerId");//获取trggier传来的值,同一个job通过trggier值不同而执行不同任务
            await Task.Run(() =>
            {
                //Random rd = new Random();
                try
                {
                    //MessageBox.Show($"CustomerId={customerId}");
                    cmd(customerId);
                }
                catch (System.Exception e)
                {
                    MessageBox.Show(e.Message);
                }
                //try
                //{
                //    var c = Form1.form1.textBox1.Text;//获取界面文本值
                //    cmd(c);
                //}
                //catch (System.Exception e)
                //{
                //    MessageBox.Show(e.Message);
                //}
            });
        }

		//执行一个cmd命令
        private void cmd(String t)
        {
            var p = new Process();
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.RedirectStandardInput = true;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.CreateNoWindow = true;//不显示窗口
            p.Start();
            p.StandardInput.WriteLine(t);
            //p.StandardInput.WriteLine("exit");//执行退出,可以不要
            p.StandardInput.Flush();
        }
    }
}

IniFunc.cs

using System.Runtime.InteropServices;
using System.Text;
//https://blog.csdn.net/qq_38693757/article/details/121675847
namespace WindowsFormsApp1
{
    public static class IniFunc
    {
        /// <summary>
        /// 获取值
        /// </summary>
        /// <param name="section">段落名</param>
        /// <param name="key">键名</param>
        /// <param name="defval">读取异常是的缺省值</param>
        /// <param name="retval">键名所对应的的值,没有找到返回空值</param>
        /// <param name="size">返回值允许的大小</param>
        /// <param name="filepath">ini文件的完整路径</param>
        /// <returns></returns>
        [DllImport("kernel32.dll")]
        private static extern int GetPrivateProfileString(
            string section,
            string key,
            string defval,
            StringBuilder retval,
            int size,
            string filepath);

        /// <summary>
        /// 写入
        /// </summary>
        /// <param name="section">需要写入的段落名</param>
        /// <param name="key">需要写入的键名</param>
        /// <param name="val">写入值</param>
        /// <param name="filepath">ini文件的完整路径</param>
        /// <returns></returns>
        [DllImport("kernel32.dll")]
        private static extern int WritePrivateProfileString(
            string section,
            string key,
            string val,
            string filepath);
        /// <summary>
        /// 获取数据
        /// </summary>
        /// <param name="section">段落名</param>
        /// <param name="key">键名</param>
        /// <param name="def">没有找到时返回的默认值</param>
        /// <param name="filename">ini文件完整路径</param>
        /// <returns></returns>
        public static string getString(string section, string key, string def, string filename)
        {
            StringBuilder sb = new StringBuilder(1024);
            GetPrivateProfileString(section, key, def, sb, 1024, filename);
            return sb.ToString();
        }

        /// <summary>
        /// 写入数据
        /// </summary>
        /// <param name="section">段落名</param>
        /// <param name="key">键名</param>
        /// <param name="val">写入值</param>
        /// <param name="filename">ini文件完整路径</param>
        public static void writeString(string section, string key, string val, string filename)
        {
            WritePrivateProfileString(section, key, val, filename);
        }
    }
}

Form1.cs

using Quartz;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading.Tasks;
using Quartz.Impl;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
    	//定义静态类,便于外部访问,类似单例
        public static Form1 form1;
        public Form1()
        {
            InitializeComponent();
            form1 = this;
        }

        private string filename = null;
		//获取ini文件路径
        private void Form1_Load(object sender, EventArgs e)
        {
            filename = Application.StartupPath + "\\config.ini";
            //MessageBox.Show(filename);
        }
		//按钮点击后,显示ini,同时执行定时任务
        private void button1_Click(object sender, EventArgs e)
        {
        	//获取ini值
            string job1 = IniFunc.getString("Information", "job1", null, filename);
            string job2 = IniFunc.getString("Information", "job2", null, filename);
            //显示在界面上
            textBox1.Text = job1;
            textBox2.Text = job2;
            //执行定时任务
            Task(job1,job2);
        }

		//执行定时任务
        public async void Task(string cmd1,string cmd2) {
        	//构建scheduler管理器
            StdSchedulerFactory factory = new StdSchedulerFactory();
            IScheduler scheduler = await factory.GetScheduler();
            await scheduler.Start();//3.7.2版本官网是先执行,再加入任务,意思是可以动态添加,老博客都是后执行
			//定义任务:WithIdentity("a")是任务的识别码Key,这个主要和trigger关联用,可以是KV,也可以是K
            IJobDetail job = JobBuilder.Create<Job>()
                .WithIdentity("a")
                .Build();
			//这里的模式是一个job对于若干个trigger,所以需要先添加job,然后trigger去关联这个job
            await scheduler.AddJob(job, replace: true, storeNonDurableWhileAwaitingScheduling: true);
			//定义trigger,并关联job,并使用JobData(JobDataMap)传值
            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity("trigger1")
                //.StartNow()
                .ForJob("a")
                .UsingJobData("CustomerId", cmd1)
                .WithSimpleSchedule(x => x
                    .WithIntervalInSeconds(5)//5秒一次
                    .RepeatForever())
                .Build();

            ITrigger trigger2 = TriggerBuilder.Create()
                .WithIdentity("trigger2")
                //.StartNow()
                .ForJob("a")
                .UsingJobData("CustomerId", cmd2)
                .WithSimpleSchedule(x => x
                    .WithIntervalInSeconds(7)//7秒一次
                    .RepeatForever())
                .Build();

			//添加触发器,普通多任务是这样的await scheduler.ScheduleJob(job,trigger),但是这里是单任务多触发
            await scheduler.ScheduleJob(trigger);
            await scheduler.ScheduleJob(trigger2);
            MessageBox.Show("任务开始");
        }

    }
}

config.ini

[Information]
job1=D:\phpStudy\php\php-7.0.12-nts\php.exe  D:\phpStudy\WWW\tp3\index.php Home/Index/queryAndWrite
job2=D:\phpStudy\php\php-7.0.12-nts\php.exe  D:\phpStudy\WWW\tp3\index.php Home/Index/queryAndWrite2

简易定时任务工具雏形

在这里插入图片描述

官网的例子才是经典的,去看看:

  • quartz.net:https://www.quartz-scheduler.net/documentation/best-practices.html#static-job-key
  • API:https://quartznet.sourceforge.io/apidoc/3.0/html/
  • 参考:https://blog.csdn.net/qq_46104221/article/details/130578236

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

为什么说数据安全运维难?有好用的数据安全运维平台吗?

随着息技术的快速发展&#xff0c;不少企业在实行数字化转型&#xff0c;同时也面临着越来越多的数据安全运维挑战。不少企业都觉得数据安全运维难&#xff0c;都在找好用的数据安全运维平台。今天我们就来聊聊为什么说数据安全运维难&#xff1f;以及是否有好用的数据安全运维…

[MICROSAR Adaptive] --- Hello Adaptive World

Automotive E/E Architecture and AUTOSAR Adaptive Platform Vector Solution: MICROSAR Adaptive First project: Hello Adaptive World Summary 1 引言 1.1 AP诞生的历史背景 新一代电子电器架构通常将车内的节点分为三类。计算平台,预控制器和传感器执行器相关的节点,…

家用电脑做服务器,本地服务器搭建,公网IP申请,路由器改桥接模式,拨号上网

先浇一盆冷水&#xff01; 我不知道其他运营商是什么情况。联通的运营商公网IP端口 80、8080、443 都会被屏蔽掉&#xff0c;想要开放必须企业备案&#xff08;个人不行&#xff09;才可以。也就是说&#xff0c;只能通过其他端口进行showtime了。 需要哪些东西&#xff1f; 申…

Spring Boot中使用Spring Data JPA访问MySQL

Spring Data JPA是Spring框架提供的用于简化JPA&#xff08;Java Persistence API&#xff09;开发的数据访问层框架。它通过提供一组便捷的API和工具&#xff0c;简化了对JPA数据访问的操作&#xff0c;同时也提供了一些额外的功能&#xff0c;比如动态查询、分页、排序等。 …

数据分析:职场不可或缺的技能

前言 在当今数字化时代&#xff0c;数据分析已经变得越来越不可或缺。不论你从事哪个行业&#xff0c;不论你在职场的哪个阶段&#xff0c;数据分析技能都将成为你在工作中脱颖而出的秘密武器。本文将阐明数据分析的重要性&#xff0c;以及如何学习数据分析&#xff0c;以及如…

MobaXterm配置SSHTunnel

本地与远程服务器之间存在防火墙&#xff0c;防火墙只允许SSH端口通过&#xff0c;为访问远程服务器&#xff0c;我们可以借助MobaXterm来与SSH服务器建立隧道&#xff0c;使得防火墙外的用户能够访问远程服务器 配置 打开SSHTunnel 新建SSH tunnel 点击开启就生效了&…

多门店自助点餐+外卖二合一小程序源码系统 带完整搭建教程

随着餐饮业的快速发展和互联网技术的不断进步&#xff0c;越来越多的餐厅开始采用自助点餐和外卖服务。市场上许多的外卖小程序APP应运而生。下面罗峰来给大家介绍一款多门店自助点餐外卖二合一小程序源码系统。该系统结合了自助点餐和外卖服务的优势&#xff0c;为餐厅提供了一…

测试老鸟整理,Postman加密接口测试-Rsa/Aes对参数加密(详细总结)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 一些问题 postma…

前端框架Vue学习 ——(五)前端工程化Vue-cli脚手架

文章目录 Vue-cliVue项目-创建Vue项目-目录结构Vue项目-启动Vue项目-配置端口Vue项目开发流程 Vue-cli 介绍&#xff1a;Vue-cli 是 Vue 官方提供的一个脚手架&#xff0c;用于快速生成一个 Vue 的项目模版 安装 NodeJS安装 Vue-cli npm install -g vue/cliVue项目-创建 图…

Java代码如何对Excel文件进行zip压缩

1&#xff1a;新建 ZipUtils 工具类 package com.ly.cloud.datacollection.util;import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.URLEncoder; import ja…

iOS Crash 治理:淘宝VisionKitCore 问题修复

本文通过逆向系统&#xff0c;阅读汇编指令&#xff0c;逐步找到源码&#xff0c;定位到了 iOS 16.0.<iOS 16.2 WKWebView 的系统bug 。同时苹果已经在新版本修复了 Bug&#xff0c;对于巨大的存量用户&#xff0c;仍旧会造成日均 Crash pv 1200 uv 1000&#xff0c; 最终通…

爬虫采集外卖数据用于竞争对手分析

因为我无法直接编写和运行代码。但我可以为大家提供编写爬虫程序的一般步骤和方法&#xff1a; 1、导入所需库&#xff1a;在Python中&#xff0c;您可以使用requests库来发送HTTP请求&#xff0c;并使用BeautifulSoup库来解析HTML。 import requests from bs4 import Beautif…

Web服务器实战

网站需求 1.基于域名www.openlab.com可以访问网站内容为 welcome to openlab!!! 2.给该公司创建三个网站目录分别显示学生信息&#xff0c;教学资料和缴费网站&#xff0c;基于www.openlab.com/student 网站访问学生信息&#xff0c;www.openlab.com/data网站访问教学资料 www…

Vue路由重定向

一、Vue路由-重定向 1.问题 网页打开时&#xff0c; url 默认是 / 路径&#xff0c;如果未匹配到组件时&#xff0c;会出现空白 2.解决方案 重定向 → 匹配 / 后, 强制跳转 /home 路径 3.语法 { path: 匹配路径, redirect: 重定向到的路径 }, 比如&#xff1a; { path:/ …

AI:61-基于深度学习的草莓病害识别

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌在这个漫长的过程,中途遇到了不少问题,但是…

在jupyter中使用R

如果想在Jupyter Notebook中使用R语言&#xff0c;以下几个步骤操作可行&#xff1a; 1、启动Anaconda Prompt 2、进入R的安装位置&#xff0c;切换到R的安装位置&#xff1a;D:\Program Files\R\R-3.4.3\bin&#xff0c;启动R&#xff0c;具体代码操作步骤如下&#xff0c;在…

gitlab 设置 分支只读

一&#xff0c;设置master分支只读&#xff0c; 并且只有Maintainers 拥有合并权限。 二&#xff0c;设置成员权限 改为developer 三&#xff0c;邀请成员 点击右上角 Invite Members

iview table 表格合并单元格

一、如图所示 二、实现方式 表格用提供的span-method属性 <template><Table ref"table" border :span-method"handleSpan" :row-key"true" :columns"tableColumns" :data"tableData"no-data-text"暂无数据&…

接口测试及接口测试工具

首先&#xff0c;什么是接口呢&#xff1f; 接口一般来说有两种&#xff0c;一种是程序内部的接口&#xff0c;一种是系统对外的接口。 系统对外的接口&#xff1a;比如你要从别的网站或服务器上获取资源或信息&#xff0c;别人肯定不会把数据库共享给你&#xff0c;他只能给你…

AJAX-解决回调函数地狱问题

一、同步代码和异步代码 1.同步代码 浏览器是按照我们书写代码的顺序一行一行地执行程序的。浏览器会等待代码的解析和工作&#xff0c;在上一行完成之后才会执行下一行。这也使得它成为一个同步程序。 总结来说&#xff1a;逐行执行&#xff0c;需原地等待结果后&#xff0…