refactor: 优化项目配置、实体类和OSS服务
1. 调整RabbitMQ队列配置为新的业务队列 2. 修正Book实体类的列名映射为驼峰命名 3. 重构OSS服务的复制方法,支持自定义目标路径 4. 完善BookCreatedHandler,动态获取路由键并统一文件存储路径
This commit is contained in:
@ -13,6 +13,11 @@ namespace QuestionLibraryMQConsumer.Entities
|
|||||||
[SugarTable("book")]
|
[SugarTable("book")]
|
||||||
public partial class Book : SqlSugarBaseEntity
|
public partial class Book : SqlSugarBaseEntity
|
||||||
{
|
{
|
||||||
|
public Book()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Desc:主键id
|
/// Desc:主键id
|
||||||
/// Default:
|
/// Default:
|
||||||
@ -34,7 +39,7 @@ namespace QuestionLibraryMQConsumer.Entities
|
|||||||
/// Default:
|
/// Default:
|
||||||
/// Nullable:False
|
/// Nullable:False
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "totalpage")]
|
[SugarColumn(ColumnName = "totalPage")]
|
||||||
public int TotalPage { get; set; }
|
public int TotalPage { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -42,7 +47,7 @@ namespace QuestionLibraryMQConsumer.Entities
|
|||||||
/// Default:
|
/// Default:
|
||||||
/// Nullable:False
|
/// Nullable:False
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "verifypage")]
|
[SugarColumn(ColumnName = "verifyPage")]
|
||||||
public int VerifyPage { get; set; }
|
public int VerifyPage { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -58,7 +63,7 @@ namespace QuestionLibraryMQConsumer.Entities
|
|||||||
/// Default:
|
/// Default:
|
||||||
/// Nullable:True
|
/// Nullable:True
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "pdfurl")]
|
[SugarColumn(ColumnName = "pdfUrl")]
|
||||||
public string PdfUrl { get; set; }
|
public string PdfUrl { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -106,7 +111,7 @@ namespace QuestionLibraryMQConsumer.Entities
|
|||||||
/// Default:
|
/// Default:
|
||||||
/// Nullable:True
|
/// Nullable:True
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "backcover")]
|
[SugarColumn(ColumnName = "backCover")]
|
||||||
public string BackCover { get; set; }
|
public string BackCover { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -114,7 +119,7 @@ namespace QuestionLibraryMQConsumer.Entities
|
|||||||
/// Default:
|
/// Default:
|
||||||
/// Nullable:True
|
/// Nullable:True
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "pdfpreviewurl")]
|
[SugarColumn(ColumnName = "pdfPreviewUrl")]
|
||||||
public string PdfPreviewUrl { get; set; }
|
public string PdfPreviewUrl { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -130,7 +135,7 @@ namespace QuestionLibraryMQConsumer.Entities
|
|||||||
/// Default:
|
/// Default:
|
||||||
/// Nullable:True
|
/// Nullable:True
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "downloadbookpagepdfname")]
|
[SugarColumn(ColumnName = "downloadBookPagePdfName")]
|
||||||
public string Downloadbookpagepdfname { get; set; }
|
public string Downloadbookpagepdfname { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -138,7 +143,7 @@ namespace QuestionLibraryMQConsumer.Entities
|
|||||||
/// Default:b'0'
|
/// Default:b'0'
|
||||||
/// Nullable:False
|
/// Nullable:False
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "is_deleted")]
|
[SugarColumn(ColumnName = "isDeleted")]
|
||||||
public bool IsDeleted { get; set; }
|
public bool IsDeleted { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -146,7 +151,7 @@ namespace QuestionLibraryMQConsumer.Entities
|
|||||||
/// Default:
|
/// Default:
|
||||||
/// Nullable:True
|
/// Nullable:True
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "created_by")]
|
[SugarColumn(ColumnName = "createdBy")]
|
||||||
public long? CreatedBy { get; set; }
|
public long? CreatedBy { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -154,7 +159,7 @@ namespace QuestionLibraryMQConsumer.Entities
|
|||||||
/// Default:
|
/// Default:
|
||||||
/// Nullable:False
|
/// Nullable:False
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "created_time")]
|
[SugarColumn(ColumnName = "createdTime")]
|
||||||
public DateTime CreatedTime { get; set; }
|
public DateTime CreatedTime { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -162,7 +167,7 @@ namespace QuestionLibraryMQConsumer.Entities
|
|||||||
/// Default:
|
/// Default:
|
||||||
/// Nullable:True
|
/// Nullable:True
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "updated_by")]
|
[SugarColumn(ColumnName = "updatedBy")]
|
||||||
public long? UpdatedBy { get; set; }
|
public long? UpdatedBy { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -170,7 +175,7 @@ namespace QuestionLibraryMQConsumer.Entities
|
|||||||
/// Default:
|
/// Default:
|
||||||
/// Nullable:True
|
/// Nullable:True
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "updated_time")]
|
[SugarColumn(ColumnName = "updatedTime")]
|
||||||
public DateTime? UpdatedTime { get; set; }
|
public DateTime? UpdatedTime { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -194,7 +199,8 @@ namespace QuestionLibraryMQConsumer.Entities
|
|||||||
/// Default:
|
/// Default:
|
||||||
/// Nullable:True
|
/// Nullable:True
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "source_id")]
|
[SugarColumn(ColumnName = "sourceId")]
|
||||||
public long SourceId { get; set; }
|
public long SourceId { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ namespace QuestionLibraryMQConsumer.Entities
|
|||||||
///其他系统
|
///其他系统
|
||||||
///</summary>
|
///</summary>
|
||||||
[SugarTable("other_system")]
|
[SugarTable("other_system")]
|
||||||
public partial class OtherSystem : SqlSugarBaseEntity
|
public partial class OtherSystem
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Desc:主键id
|
/// Desc:主键id
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
using QuestionLibraryMQConsumer.Data;
|
using Microsoft.Extensions.Options;
|
||||||
|
using QuestionLibraryMQConsumer.Configuration;
|
||||||
|
using QuestionLibraryMQConsumer.Data;
|
||||||
using QuestionLibraryMQConsumer.Entities;
|
using QuestionLibraryMQConsumer.Entities;
|
||||||
using QuestionLibraryMQConsumer.Models;
|
using QuestionLibraryMQConsumer.Models;
|
||||||
using QuestionLibraryMQConsumer.Services;
|
using QuestionLibraryMQConsumer.Services;
|
||||||
@ -6,6 +8,7 @@ using RabbitMQ.Client;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -22,19 +25,26 @@ namespace QuestionLibraryMQConsumer.Handlers
|
|||||||
private readonly ILogger<BookCreatedHandler> _logger;
|
private readonly ILogger<BookCreatedHandler> _logger;
|
||||||
private readonly QuestionLibraryDb _db;
|
private readonly QuestionLibraryDb _db;
|
||||||
private readonly IOssService _ossService;
|
private readonly IOssService _ossService;
|
||||||
|
private readonly string _routingKey;
|
||||||
|
|
||||||
public string RoutingKey => "questionLibrary.book.created";
|
public string RoutingKey => _routingKey;
|
||||||
public Type MessageType => typeof(BookCreatedMessage);
|
public Type MessageType => typeof(BookCreatedMessage);
|
||||||
public bool RequiresManualAck => false;
|
public bool RequiresManualAck => false;
|
||||||
|
|
||||||
public BookCreatedHandler(
|
public BookCreatedHandler(
|
||||||
ILogger<BookCreatedHandler> logger,
|
ILogger<BookCreatedHandler> logger,
|
||||||
QuestionLibraryDb db,
|
QuestionLibraryDb db,
|
||||||
IOssService ossService)
|
IOssService ossService,
|
||||||
|
IOptions<RabbitMqOptions> rabbitMqOptions)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_db = db;
|
_db = db;
|
||||||
_ossService = ossService;
|
_ossService = ossService;
|
||||||
|
|
||||||
|
var handlerTypeName = nameof(BookCreatedHandler);
|
||||||
|
_routingKey = rabbitMqOptions.Value.Queues
|
||||||
|
.FirstOrDefault(q => q.HandlerType == handlerTypeName)
|
||||||
|
?.RoutingKey ?? string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task HandleJsonAsync(string messageJson, CancellationToken cancellationToken)
|
public async Task HandleJsonAsync(string messageJson, CancellationToken cancellationToken)
|
||||||
@ -86,17 +96,20 @@ namespace QuestionLibraryMQConsumer.Handlers
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(pdfUrl))
|
if (!string.IsNullOrEmpty(pdfUrl))
|
||||||
{
|
{
|
||||||
copyTasks.Add(CopyUrlAsync("PdfUrl", pdfUrl, otherSystem, newUrl => pdfUrl = newUrl, cancellationToken));
|
var pdfExt = Path.GetExtension(pdfUrl);
|
||||||
|
copyTasks.Add(CopyUrlAsync("PdfUrl", pdfUrl, $"book/{message.BookId}/book{pdfExt}", otherSystem, newUrl => pdfUrl = newUrl, cancellationToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(coverUrl))
|
if (!string.IsNullOrEmpty(coverUrl))
|
||||||
{
|
{
|
||||||
copyTasks.Add(CopyUrlAsync("CoverUrl", coverUrl, otherSystem, newUrl => coverUrl = newUrl, cancellationToken));
|
var coverExt = Path.GetExtension(coverUrl);
|
||||||
|
copyTasks.Add(CopyUrlAsync("CoverUrl", coverUrl, $"book/{message.BookId}/cover{coverExt}", otherSystem, newUrl => coverUrl = newUrl, cancellationToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(backCoverUrl))
|
if (!string.IsNullOrEmpty(backCoverUrl))
|
||||||
{
|
{
|
||||||
copyTasks.Add(CopyUrlAsync("BackCoverUrl", backCoverUrl, otherSystem, newUrl => backCoverUrl = newUrl, cancellationToken));
|
var backCoverExt = Path.GetExtension(backCoverUrl);
|
||||||
|
copyTasks.Add(CopyUrlAsync("BackCoverUrl", backCoverUrl, $"book/{message.BookId}/backCover{backCoverExt}", otherSystem, newUrl => backCoverUrl = newUrl, cancellationToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (copyTasks.Count > 0)
|
if (copyTasks.Count > 0)
|
||||||
@ -130,11 +143,11 @@ namespace QuestionLibraryMQConsumer.Handlers
|
|||||||
_logger.LogInformation("书籍 {BookId} 创建成功", message.BookId);
|
_logger.LogInformation("书籍 {BookId} 创建成功", message.BookId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task CopyUrlAsync(string fieldName, string originalPath, OtherSystem otherSystem, Action<string> setNewPath, CancellationToken cancellationToken)
|
private async Task CopyUrlAsync(string fieldName, string originalPath, string targetPath, OtherSystem otherSystem, Action<string> setNewPath, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var newPath = await _ossService.CopyToOwnBucketAsync(originalPath, otherSystem.BucketName, cancellationToken);
|
var newPath = await _ossService.CopyToOwnBucketAsync(originalPath, otherSystem.BucketName, targetPath, cancellationToken);
|
||||||
setNewPath(newPath);
|
setNewPath(newPath);
|
||||||
_logger.LogInformation("{FieldName} OSS复制成功: {OriginalPath} -> {NewPath}", fieldName, originalPath, newPath);
|
_logger.LogInformation("{FieldName} OSS复制成功: {OriginalPath} -> {NewPath}", fieldName, originalPath, newPath);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,5 +9,5 @@ public interface IOssService
|
|||||||
/// <param name="sourceBucket">源bucket名称</param>
|
/// <param name="sourceBucket">源bucket名称</param>
|
||||||
/// <param name="cancellationToken">取消令牌</param>
|
/// <param name="cancellationToken">取消令牌</param>
|
||||||
/// <returns>复制后的新URL</returns>
|
/// <returns>复制后的新URL</returns>
|
||||||
Task<string> CopyToOwnBucketAsync(string sourcePath, string sourceBucket, CancellationToken cancellationToken = default);
|
Task<string> CopyToOwnBucketAsync(string sourcePath, string sourceBucket, string targetPath, CancellationToken cancellationToken = default);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,7 @@ public class OssService : IOssService
|
|||||||
_ossOptions = ossOptions.Value;
|
_ossOptions = ossOptions.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> CopyToOwnBucketAsync(string sourcePath, string sourceBucket, CancellationToken cancellationToken = default)
|
public async Task<string> CopyToOwnBucketAsync(string sourcePath, string sourceBucket, string targetPath, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(sourcePath))
|
if (string.IsNullOrEmpty(sourcePath))
|
||||||
{
|
{
|
||||||
@ -34,13 +34,13 @@ public class OssService : IOssService
|
|||||||
var client = new OssClient(_ossOptions.Endpoint, _ossOptions.AccessKeyID, _ossOptions.AccessKeySecret);
|
var client = new OssClient(_ossOptions.Endpoint, _ossOptions.AccessKeyID, _ossOptions.AccessKeySecret);
|
||||||
|
|
||||||
// 执行跨bucket复制
|
// 执行跨bucket复制
|
||||||
var request = new CopyObjectRequest(sourceBucket, objectKey, _ossOptions.BucketName, objectKey);
|
var request = new CopyObjectRequest(sourceBucket, objectKey, _ossOptions.BucketName, targetPath);
|
||||||
var result = client.CopyObject(request);
|
var result = client.CopyObject(request);
|
||||||
|
|
||||||
_logger.LogInformation("OSS跨bucket复制成功: {SourceBucket}/{ObjectKey} -> {TargetBucket}/{TargetKey}, ETag: {ETag}",
|
_logger.LogInformation("OSS跨bucket复制成功: {SourceBucket}/{ObjectKey} -> {TargetBucket}/{TargetKey}, ETag: {ETag}",
|
||||||
sourceBucket, objectKey, _ossOptions.BucketName, objectKey, result.ETag);
|
sourceBucket, objectKey, _ossOptions.BucketName, targetPath, result.ETag);
|
||||||
|
|
||||||
return objectKey;
|
return targetPath;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -10,25 +10,10 @@
|
|||||||
"PrefetchCount": 10,
|
"PrefetchCount": 10,
|
||||||
"Queues": [
|
"Queues": [
|
||||||
{
|
{
|
||||||
"QueueName": "questionLibrary.book.created.queue",
|
"QueueName": "mq.book.push",
|
||||||
"ExchangeName": "icr.direct",
|
"ExchangeName": "ex.book.direct",
|
||||||
"RoutingKey": "questionLibrary.book.created",
|
"RoutingKey": "rk.book.push",
|
||||||
"Durable": true,
|
"HandlerType": "BookCreatedHandler",
|
||||||
"Exclusive": false,
|
|
||||||
"AutoDelete": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"QueueName": "questionLibrary.book.created.queue",
|
|
||||||
"ExchangeName": "question.library.exchange.dev",
|
|
||||||
"RoutingKey": "questionLibrary.book.created",
|
|
||||||
"Durable": true,
|
|
||||||
"Exclusive": false,
|
|
||||||
"AutoDelete": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"QueueName": "questionLibrary.book.created.queue",
|
|
||||||
"ExchangeName": "question.library.exchange",
|
|
||||||
"RoutingKey": "questionLibrary.book.created",
|
|
||||||
"Durable": true,
|
"Durable": true,
|
||||||
"Exclusive": false,
|
"Exclusive": false,
|
||||||
"AutoDelete": false
|
"AutoDelete": false
|
||||||
|
|||||||
Reference in New Issue
Block a user