diff --git a/.idea/.idea.Bunny.WebApi/.idea/GitCommitMessageStorage.xml b/.idea/.idea.Bunny.WebApi/.idea/GitCommitMessageStorage.xml index 3b56900..e4fd56a 100644 --- a/.idea/.idea.Bunny.WebApi/.idea/GitCommitMessageStorage.xml +++ b/.idea/.idea.Bunny.WebApi/.idea/GitCommitMessageStorage.xml @@ -2,19 +2,7 @@ \ No newline at end of file diff --git a/Bunny.Common/Bunny.Common.csproj b/Bunny.Common/Bunny.Common.csproj index e27855b..67a2885 100644 --- a/Bunny.Common/Bunny.Common.csproj +++ b/Bunny.Common/Bunny.Common.csproj @@ -19,6 +19,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Bunny.Common/Connect/MinioContext.cs b/Bunny.Common/Connect/MinioContext.cs new file mode 100644 index 0000000..34e0a64 --- /dev/null +++ b/Bunny.Common/Connect/MinioContext.cs @@ -0,0 +1,31 @@ +using Bunny.Common.Utils; +using Microsoft.AspNetCore.Builder; +using Minio; + +namespace Bunny.Common.Connect; + +public static class MinioContext +{ + public static IMinioClient? MinioClient; + public static readonly string BucketName = AppSettings.GetConfig("Minio:BucketName"); + + public static void AddMinioContext(this WebApplicationBuilder builder) + { + var endpoint = AppSettings.GetConfig("Minio:Url"); + var accessKey = AppSettings.GetConfig("Minio:AccessKey"); + var secretKey = AppSettings.GetConfig("Minio:SecretKey"); + + MinioClient = new MinioClient().WithEndpoint(endpoint).WithCredentials(accessKey, secretKey) + // .WithSSL() // 使用HTTPS + .Build(); + Task.Run(ShowAllBucket); + } + + private static async Task ShowAllBucket() + { + var listBucketsAsync = await MinioUtil.ListBucketsAsync(); + foreach (var bucket in listBucketsAsync.Buckets) Console.WriteLine($"Minio存在的桶:{bucket.Name}"); + + Console.WriteLine("Minio 连接成功..."); + } +} \ No newline at end of file diff --git a/Bunny.Common/Connect/RedisContext.cs b/Bunny.Common/Connect/RedisContext.cs index e93dd71..37d2e3c 100644 --- a/Bunny.Common/Connect/RedisContext.cs +++ b/Bunny.Common/Connect/RedisContext.cs @@ -1,13 +1,14 @@ -using StackExchange.Redis; +using Microsoft.AspNetCore.Builder; +using StackExchange.Redis; namespace Bunny.Common.Connect; -public class RedisContext +public static class RedisContext { public static IDatabase RedisDatabase; private static readonly EndPointCollection EndPointCollection = new(); - public static void Initial() + public static void AddRedisContext(this WebApplicationBuilder builder) { // 获取端口等配置信息 var host = AppSettings.GetConfig("Redis:Host"); diff --git a/Bunny.Common/Utils/MinioUtil.cs b/Bunny.Common/Utils/MinioUtil.cs new file mode 100644 index 0000000..c5e2190 --- /dev/null +++ b/Bunny.Common/Utils/MinioUtil.cs @@ -0,0 +1,205 @@ +using Bunny.Common.Connect; +using Bunny.Common.Exception; +using Bunny.Dao.Entity.Constant; +using Microsoft.AspNetCore.Http; +using Microsoft.IdentityModel.Tokens; +using Minio.DataModel; +using Minio.DataModel.Args; +using Minio.DataModel.Result; +using Minio.Exceptions; + +namespace Bunny.Common.Utils; + +public static class MinioUtil +{ + /// + /// 创建新的桶,如果不存在则创建 + /// + /// 桶名称 + public static async Task MakeBucketAsync(string bucketName) + { + // 判断桶名称是否初始化 + bucketName = bucketName.IsNullOrEmpty() ? MinioContext.BucketName : bucketName; + // minio客户端 + var minioClient = MinioContext.MinioClient; + + try + { + var found = await BucketExistsAsync(bucketName); + if (!found) await minioClient!.MakeBucketAsync(new MakeBucketArgs().WithBucket(bucketName)); + } + catch (MinioException e) + { + Console.WriteLine(e); + throw new BunnyException(ExceptionConstant.FileSystemException); + } + } + + /// + /// 列出所有的桶 + /// + public static async Task ListBucketsAsync() + { + var minioClient = MinioContext.MinioClient; + try + { + var listAllMyBucketsResult = await minioClient!.ListBucketsAsync(); + return listAllMyBucketsResult; + } + catch (MinioException e) + { + Console.WriteLine(e); + throw new BunnyException(ExceptionConstant.FileSystemException); + } + } + + /// + /// 判断桶是否存在 + /// + /// + /// + public static async Task BucketExistsAsync(string bucketName) + { + // 判断桶名称是否初始化 + bucketName = bucketName.IsNullOrEmpty() ? MinioContext.BucketName : bucketName; + // minio客户端 + var minioClient = MinioContext.MinioClient; + + return await minioClient!.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName)); + } + + /// + /// 移出桶 + /// + /// 桶名称 + public static async Task RemoveBucketAsync(string bucketName) + { + // 判断桶名称是否初始化 + bucketName = bucketName.IsNullOrEmpty() ? MinioContext.BucketName : bucketName; + // minio客户端 + var minioClient = MinioContext.MinioClient!; + + try + { + // 如果存在则移除 + var found = await BucketExistsAsync(bucketName); + if (found) await minioClient.RemoveBucketAsync(new RemoveBucketArgs().WithBucket(bucketName)); + else Console.WriteLine("桶不存在"); + } + catch (MinioException e) + { + Console.WriteLine(e); + throw new BunnyException(ExceptionConstant.FileSystemException); + } + } + + /// + /// 查看桶的版本信息 + /// + /// 桶名称 + public static async Task GetVersioningInfoAsync(string bucketName) + { + // 判断桶名称是否初始化 + bucketName = bucketName.IsNullOrEmpty() ? MinioContext.BucketName : bucketName; + // minio客户端 + var minioClient = MinioContext.MinioClient!; + + try + { + var found = await BucketExistsAsync(bucketName); + if (!found) Console.WriteLine("桶不存在"); + + return await minioClient.GetVersioningAsync(new GetVersioningArgs().WithBucket(bucketName)); + } + catch (MinioException e) + { + Console.WriteLine(e); + throw new BunnyException(ExceptionConstant.FileSystemException); + } + } + + /// + /// 上传文件 + /// + /// 桶名称 + /// 文件 + public static async Task PutObjectAsync(IFormFile file, string? bucketName = default) + { + // 判断桶名称是否初始化 + bucketName = bucketName.IsNullOrEmpty() ? MinioContext.BucketName : bucketName; + // minio客户端 + var minioClient = MinioContext.MinioClient!; + + var guid = Guid.NewGuid().ToString(); + var fileName = guid + file.FileName; + try + { + var found = await BucketExistsAsync(bucketName!); + if (!found) await MakeBucketAsync(bucketName!); + + await minioClient.PutObjectAsync(new PutObjectArgs().WithBucket(bucketName).WithObject(fileName) + .WithStreamData(file.OpenReadStream()).WithObjectSize(file.Length)); + } + catch (MinioException e) + { + Console.WriteLine(e); + throw new BunnyException(ExceptionConstant.FileSystemException); + } + } + + /// + /// 获取文件对象信息 + /// + /// 桶名称 + /// 文件名 + public static async Task GetObjectAsync(string filename, string? bucketName = default) + { + // 判断桶名称是否初始化 + bucketName = bucketName.IsNullOrEmpty() ? MinioContext.BucketName : bucketName; + // minio客户端 + var minioClient = MinioContext.MinioClient!; + + try + { + var statObjectArgs = new StatObjectArgs().WithBucket(bucketName).WithObject(filename); + await minioClient.StatObjectAsync(statObjectArgs); + + var getObjectArgs = new GetObjectArgs().WithBucket(bucketName).WithObject(filename).WithFile(filename); + return await minioClient.GetObjectAsync(getObjectArgs); + } + catch (MinioException e) + { + Console.WriteLine(e); + throw new BunnyException(ExceptionConstant.FileSystemException); + } + } + + + /// + /// 桶中内容状态 + /// + /// 桶名称 + /// 文件名 + public static async Task StatObject(string filename, string? bucketName = default) + { + // 判断桶名称是否初始化 + bucketName = bucketName.IsNullOrEmpty() ? MinioContext.BucketName : bucketName; + // minio客户端 + var minioClient = MinioContext.MinioClient!; + + try + { + // Get the metadata of the object. + var statObjectArgs = new StatObjectArgs() + .WithBucket(bucketName) + .WithObject(filename); + var objectStat = await minioClient.StatObjectAsync(statObjectArgs); + return objectStat; + } + catch (MinioException e) + { + Console.WriteLine(e); + throw new BunnyException(ExceptionConstant.FileSystemException); + } + } +} \ No newline at end of file diff --git a/Bunny.Service/Bunny.Service.csproj b/Bunny.Service/Bunny.Service.csproj index 4bb6028..cb95e0e 100644 --- a/Bunny.Service/Bunny.Service.csproj +++ b/Bunny.Service/Bunny.Service.csproj @@ -9,6 +9,7 @@ + diff --git a/Bunny.Service/IService/IJobService.cs b/Bunny.Service/IService/IJobService.cs new file mode 100644 index 0000000..50ddca4 --- /dev/null +++ b/Bunny.Service/IService/IJobService.cs @@ -0,0 +1,9 @@ +namespace Bunny.Service.IService; + +public interface IJobService +{ + /// + /// 开启一个简单的工作 + /// + void StartSimpleJob(); +} \ No newline at end of file diff --git a/Bunny.Service/IService/Service/JobService.cs b/Bunny.Service/IService/Service/JobService.cs new file mode 100644 index 0000000..e127754 --- /dev/null +++ b/Bunny.Service/IService/Service/JobService.cs @@ -0,0 +1,40 @@ +using Bunny.Service.Job; +using Quartz; +using Quartz.Impl; + +namespace Bunny.Service.IService.Service; + +public class JobService : IJobService +{ + /// + /// 开启一个简单的工作 + /// https://www.youtube.com/watch?v=CuHIScZKup8&list=PLSi1BNmQ61ZohCcl43UdAksg7X3_TSmly&index=6 + /// + public void StartSimpleJob() + { + var schedulerFactory = new StdSchedulerFactory(); + // TODO 如果使用异步,必须使用await 和 async + // var scheduler = schedulerFactory.GetScheduler(); + var scheduler = schedulerFactory.GetScheduler().GetAwaiter().GetResult(); + + var jobDetail = JobBuilder.Create() + .UsingJobData("username", "用户名") + .UsingJobData("password", "密码") + .WithIdentity("simpleJob", "简单的JOB") + .Build(); + var trigger = TriggerBuilder.Create() + .WithIdentity("testTrigger", "测试发出器") + .StartNow() + // 每隔5秒执行一次,一共重复10次 + .WithSimpleSchedule(x => x.WithIntervalInSeconds(5).WithRepeatCount(10)) + .Build(); + + // 使用同步方法 + scheduler.ScheduleJob(jobDetail, trigger).GetAwaiter().GetResult(); + scheduler.Start().GetAwaiter().GetResult(); + + // TODO 使用异步 + // await _scheduler.ScheduleJob(jobDetail, trigger); + // await _scheduler.Start(); + } +} \ No newline at end of file diff --git a/Bunny.Service/Job/SimJob.cs b/Bunny.Service/Job/SimJob.cs new file mode 100644 index 0000000..13925e0 --- /dev/null +++ b/Bunny.Service/Job/SimJob.cs @@ -0,0 +1,16 @@ +using Quartz; + +namespace Bunny.Service.Job; + +public class SimJob : IJob +{ + public Task Execute(IJobExecutionContext context) + { + Console.WriteLine("执行一个简单的任务"); + var dataMap = context.JobDetail.JobDataMap; + var username = dataMap.GetString("username"); + var password = dataMap.GetString("password"); + Console.WriteLine($"用户名:{username},密码: {password}"); + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/Bunny.Service/WebSocket/WebSocketInitial.cs b/Bunny.Service/WebSocket/WebSocketInitial.cs index 5a12c28..ee3bff0 100644 --- a/Bunny.Service/WebSocket/WebSocketInitial.cs +++ b/Bunny.Service/WebSocket/WebSocketInitial.cs @@ -1,8 +1,10 @@ -namespace Bunny.Service.WebSocket; +using Microsoft.AspNetCore.Builder; + +namespace Bunny.Service.WebSocket; public static class WebSocketInitial { - public static void Start() + public static void AddWebSocketInitial(this WebApplicationBuilder builder) { WebSocketTest.Start(); } diff --git a/Bunny.WebApi/Config/BaseConfig.cs b/Bunny.WebApi/Config/BaseConfig.cs index 21b1f6a..18d19ea 100644 --- a/Bunny.WebApi/Config/BaseConfig.cs +++ b/Bunny.WebApi/Config/BaseConfig.cs @@ -44,13 +44,15 @@ public class BaseConfig(WebApplicationBuilder builder) private void UseExtend() { // 设置过滤器 - FilterConfig.Initialize(builder); + builder.FilterConfigInitialize(); // 初始化Redis - RedisContext.Initial(); + builder.AddRedisContext(); + // 初始化Minio + builder.AddMinioContext(); // 初始化 Knife4Net 文档 - Knife4Net.Initialize(builder); + builder.AddKnife4Net(); // 启动 webSocket - WebSocketInitial.Start(); + builder.AddWebSocketInitial(); } /// diff --git a/Bunny.WebApi/Config/FilterConfig.cs b/Bunny.WebApi/Config/FilterConfig.cs index e76495b..1a93188 100644 --- a/Bunny.WebApi/Config/FilterConfig.cs +++ b/Bunny.WebApi/Config/FilterConfig.cs @@ -9,7 +9,7 @@ public static class FilterConfig /// 配置过滤器 /// /// - public static void Initialize(WebApplicationBuilder builder) + public static void FilterConfigInitialize(this WebApplicationBuilder builder) { // 添加自定义过滤器---全局异常捕获 builder.Services.AddControllers(option => diff --git a/Bunny.WebApi/Config/Knife4Net.cs b/Bunny.WebApi/Config/Knife4Net.cs index 36cb8b5..4272698 100644 --- a/Bunny.WebApi/Config/Knife4Net.cs +++ b/Bunny.WebApi/Config/Knife4Net.cs @@ -8,7 +8,7 @@ public static class Knife4Net /// /// 配置 Knife4j 文档 /// - public static void Initialize(WebApplicationBuilder builder) + public static void AddKnife4Net(this WebApplicationBuilder builder) { builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(options => diff --git a/Bunny.WebApi/Config/ServiceRegistration.cs b/Bunny.WebApi/Config/ServiceRegistration.cs index e509de0..b2e22a8 100644 --- a/Bunny.WebApi/Config/ServiceRegistration.cs +++ b/Bunny.WebApi/Config/ServiceRegistration.cs @@ -15,6 +15,7 @@ public static class ServiceRegistration builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); + builder.Services.AddScoped(); } /// diff --git a/Bunny.WebApi/Controllers/JobInitController.cs b/Bunny.WebApi/Controllers/JobInitController.cs new file mode 100644 index 0000000..a6e069b --- /dev/null +++ b/Bunny.WebApi/Controllers/JobInitController.cs @@ -0,0 +1,23 @@ +using Bunny.Dao.Result; +using Bunny.Service.IService; +using Microsoft.AspNetCore.Mvc; + +namespace Bunny.WebApi.Controllers; + +/// +/// Quartz 示例相关 +/// +[Route("/api/[controller]/[action]")] +public class JobInitController(IJobService jobService) : ControllerBase +{ + /// + /// 开启一个简单的工作 + /// + /// + [HttpPost] + public Result StartSimpleJob() + { + jobService.StartSimpleJob(); + return Result.Success(); + } +} \ No newline at end of file diff --git a/Bunny.WebApi/appsettings.json b/Bunny.WebApi/appsettings.json index f5107f7..e3ef6b2 100644 --- a/Bunny.WebApi/appsettings.json +++ b/Bunny.WebApi/appsettings.json @@ -21,5 +21,11 @@ "Password": "02120212", "DefaultDB": 6, "AsyncTimeout": 300 + }, + "Minio": { + "Url": "192.168.3.98:9000", + "AccessKey": "bunny", + "SecretKey": "02120212", + "BucketName": "test" } } \ No newline at end of file