forked from ddrilling/AsbCloudServer
Новая реализация парсинга траекторий и фабрики парсеров
This commit is contained in:
parent
108644c13d
commit
94c7e1e7c9
@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Requests.Import;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudApp.Requests.ParserOptions;
|
||||
using AsbCloudApp.Services.Parser;
|
||||
using AsbCloudInfrastructure.Services.Trajectory.Parser;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services;
|
||||
@ -12,19 +12,30 @@ public class ParserServiceFactory
|
||||
public const int IdTrajectoryFactManualParserService = 1;
|
||||
public const int IdTrajectoryPlanParserService = 2;
|
||||
|
||||
private readonly IDictionary<int, Func<IParserService>> parsers = new Dictionary<int, Func<IParserService>>
|
||||
private readonly IDictionary<int, Func<object>> parsers = new Dictionary<int, Func<object>>
|
||||
{
|
||||
{ IdTrajectoryPlanParserService, () => new TrajectoryPlanParserService() },
|
||||
{ IdTrajectoryFactManualParserService, () => new TrajectoryFactManualParserService() }
|
||||
};
|
||||
|
||||
public IParserService<TDto, TOptions> Create<TDto, TOptions>(int idImportService)
|
||||
public IParserService<TDto> GetParser<TDto>(int idParserService)
|
||||
where TDto : class, IId
|
||||
where TOptions : ParserOptionsRequestBase
|
||||
{
|
||||
var parser = parsers[idImportService].Invoke();
|
||||
if (!parsers.TryGetValue(idParserService, out var parserService))
|
||||
throw new ArgumentNullException(nameof(idParserService), "Сервис не зарегистрирован");
|
||||
|
||||
return parser as IParserService<TDto, TOptions>
|
||||
?? throw new ArgumentNullException(nameof(idImportService), "Не удалось распознать файл");
|
||||
return parserService.Invoke() as IParserService<TDto>
|
||||
?? throw new ArgumentNullException(nameof(idParserService), "Ошибка приведения типа");
|
||||
}
|
||||
|
||||
public IParserServiceWithOptions<TDto, TOptions> GetParserWithOptions<TDto, TOptions>(int idParserService)
|
||||
where TDto : class, IId
|
||||
where TOptions : IParserOptionsRequest
|
||||
{
|
||||
if (!parsers.TryGetValue(idParserService, out var parserService))
|
||||
throw new ArgumentNullException(nameof(idParserService), "Сервис не зарегистрирован");
|
||||
|
||||
return parserService.Invoke() as IParserServiceWithOptions<TDto, TOptions>
|
||||
?? throw new ArgumentNullException(nameof(idParserService), "Ошибка приведения типа");
|
||||
}
|
||||
}
|
@ -6,6 +6,8 @@ namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
|
||||
|
||||
public class TrajectoryFactManualParserService : TrajectoryParserService<TrajectoryGeoFactDto>
|
||||
{
|
||||
protected override string SheetName => "Фактическая траектория";
|
||||
|
||||
protected override ValidationResultDto<TrajectoryGeoFactDto> ParseRow(IXLRow row)
|
||||
{
|
||||
var trajectoryRow = new TrajectoryGeoFactDto
|
||||
|
@ -1,78 +1,31 @@
|
||||
using AsbCloudApp.Data.Trajectory;
|
||||
using ClosedXML.Excel;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Requests.Import;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudApp.Services.Parser;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
|
||||
|
||||
public abstract class TrajectoryParserService<T> : IParserService<T, TrajectoryParserRequest>
|
||||
public abstract class TrajectoryParserService<T> : IParserService<T>
|
||||
where T : TrajectoryGeoDto
|
||||
{
|
||||
private const int HeaderRowsCount = 2;
|
||||
private const int ColumnCount = 6;
|
||||
|
||||
protected abstract string SheetName { get; }
|
||||
|
||||
protected abstract ValidationResultDto<T> ParseRow(IXLRow row);
|
||||
|
||||
public ParserResultDto<T> Parse(Stream file, TrajectoryParserRequest options)
|
||||
public ParserResultDto<T> Parse(Stream file)
|
||||
{
|
||||
using var workbook = new XLWorkbook(file, XLEventTracking.Disabled);
|
||||
var trajectoryRows = ParseFileStream(file, options);
|
||||
|
||||
var sheet = workbook.Worksheets.FirstOrDefault(ws =>
|
||||
ws.Name.ToLower().Trim() == SheetName.ToLower().Trim())
|
||||
?? throw new FileFormatException($"Книга excel не содержит листа {SheetName}.");
|
||||
|
||||
var trajectoryRows = sheet.Parse(ParseRow, ColumnCount, HeaderRowsCount);
|
||||
return trajectoryRows;
|
||||
}
|
||||
|
||||
private ParserResultDto<T> ParseFileStream(Stream stream, TrajectoryParserRequest options)
|
||||
{
|
||||
using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled);
|
||||
return ParseWorkbook(workbook, options);
|
||||
}
|
||||
|
||||
private ParserResultDto<T> ParseWorkbook(IXLWorkbook workbook, TrajectoryParserRequest options)
|
||||
{
|
||||
var sheetTrajectory = workbook.Worksheets.FirstOrDefault(ws =>
|
||||
ws.Name.ToLower().Trim() == options.SheetName.ToLower().Trim());
|
||||
if (sheetTrajectory is null)
|
||||
throw new FileFormatException($"Книга excel не содержит листа {options.SheetName}.");
|
||||
var trajectoryRows = ParseSheet(sheetTrajectory, options);
|
||||
return trajectoryRows;
|
||||
}
|
||||
|
||||
private ParserResultDto<T> ParseSheet(IXLWorksheet sheet, TrajectoryParserRequest options)
|
||||
{
|
||||
if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < 6)
|
||||
throw new FileFormatException($"Лист {sheet.Name} содержит меньшее количество столбцов.");
|
||||
|
||||
var count = sheet.RowsUsed().Count() - options.HeaderRowsCount;
|
||||
|
||||
if (count > 1024)
|
||||
throw new FileFormatException($"Лист {sheet.Name} содержит слишком большое количество строк.");
|
||||
|
||||
if (count <= 0)
|
||||
throw new FileFormatException($"Лист {sheet.Name} некорректного формата либо пустой");
|
||||
|
||||
var trajectoryRows = new List<ValidationResultDto<T>>(count);
|
||||
var parseErrors = new List<string>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var row = sheet.Row(1 + i + options.HeaderRowsCount);
|
||||
try
|
||||
{
|
||||
var trajectoryRow = ParseRow(row);
|
||||
trajectoryRows.Add(trajectoryRow);
|
||||
}
|
||||
catch (FileFormatException ex)
|
||||
{
|
||||
parseErrors.Add(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
if (parseErrors.Any())
|
||||
throw new FileFormatException(string.Join("\r\n", parseErrors));
|
||||
|
||||
return new ParserResultDto<T>
|
||||
{
|
||||
Item = trajectoryRows
|
||||
};
|
||||
}
|
||||
}
|
@ -6,6 +6,8 @@ namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
|
||||
|
||||
public class TrajectoryPlanParserService : TrajectoryParserService<TrajectoryGeoPlanDto>
|
||||
{
|
||||
protected override string SheetName => "Плановая траектория";
|
||||
|
||||
protected override ValidationResultDto<TrajectoryGeoPlanDto> ParseRow(IXLRow row)
|
||||
{
|
||||
var trajectoryRow = new TrajectoryGeoPlanDto
|
||||
|
@ -1,6 +1,5 @@
|
||||
using System.Linq;
|
||||
using AsbCloudApp.Data.Trajectory;
|
||||
using AsbCloudApp.Requests.Import;
|
||||
using AsbCloudInfrastructure.Services;
|
||||
using Xunit;
|
||||
|
||||
@ -10,20 +9,6 @@ public class TrajectoryParserTest
|
||||
{
|
||||
private const string UsingTemplateFile = "AsbCloudWebApi.Tests.Services.Trajectory.Templates";
|
||||
|
||||
private readonly TrajectoryParserRequest planTrajectoryParserOptions = new()
|
||||
{
|
||||
IdParserService = ParserServiceFactory.IdTrajectoryPlanParserService,
|
||||
SheetName = "Плановая траектория",
|
||||
HeaderRowsCount = 2
|
||||
};
|
||||
|
||||
private readonly TrajectoryParserRequest factTrajectoryParserOptions = new()
|
||||
{
|
||||
IdParserService = ParserServiceFactory.IdTrajectoryFactManualParserService,
|
||||
SheetName = "Фактическая траектория",
|
||||
HeaderRowsCount = 2
|
||||
};
|
||||
|
||||
private static readonly ParserServiceFactory parserServiceFactory = new();
|
||||
|
||||
[Fact]
|
||||
@ -35,9 +20,8 @@ public class TrajectoryParserTest
|
||||
if (stream is null)
|
||||
Assert.Fail("Файла для импорта не существует");
|
||||
|
||||
var parserService = parserServiceFactory.Create<TrajectoryGeoPlanDto, TrajectoryParserRequest>(
|
||||
planTrajectoryParserOptions.IdParserService);
|
||||
var trajectoryRows = parserService.Parse(stream, planTrajectoryParserOptions);
|
||||
var parserService = parserServiceFactory.GetParser<TrajectoryGeoPlanDto>(ParserServiceFactory.IdTrajectoryPlanParserService);
|
||||
var trajectoryRows = parserService.Parse(stream);
|
||||
|
||||
Assert.Equal(3, trajectoryRows.Item.Count());
|
||||
}
|
||||
@ -51,9 +35,8 @@ public class TrajectoryParserTest
|
||||
if (stream is null)
|
||||
Assert.Fail("Файла для импорта не существует");
|
||||
|
||||
var parserService = parserServiceFactory.Create<TrajectoryGeoFactDto, TrajectoryParserRequest>(
|
||||
factTrajectoryParserOptions.IdParserService);
|
||||
var trajectoryRows = parserService.Parse(stream, factTrajectoryParserOptions);
|
||||
var parserService = parserServiceFactory.GetParser<TrajectoryGeoFactDto>(ParserServiceFactory.IdTrajectoryFactManualParserService);
|
||||
var trajectoryRows = parserService.Parse(stream);
|
||||
|
||||
Assert.Equal(4, trajectoryRows.Item.Count());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user