From f7384b9afc92ca324f62811c908531552b6fbff6 Mon Sep 17 00:00:00 2001 From: zhangqi <2794379662@qq.com> Date: Tue, 23 Feb 2021 09:51:50 +0800 Subject: [PATCH] init project --- .gitignore | 7 ++ Domain/AggregateModel/AppAggregate/App.cs | 23 +++++ .../AppAggregate/IAppRepository.cs | 15 +++ .../LinkAggregate/ILinkRepository.cs | 16 ++++ Domain/AggregateModel/LinkAggregate/Link.cs | 61 ++++++++++++ Domain/Domain.csproj | 12 +++ Domain/SeedWork/Entity.cs | 92 +++++++++++++++++++ Domain/SeedWork/Enumeration.cs | 74 +++++++++++++++ Domain/SeedWork/IAggregateRoot.cs | 6 ++ Domain/SeedWork/IRepository.cs | 7 ++ Domain/SeedWork/IUnitOfWork.cs | 12 +++ Domain/SeedWork/ValueObject.cs | 48 ++++++++++ Infrastructure/Infrastructure.csproj | 11 +++ Infrastructure/Repositories/AppRepository.cs | 25 +++++ Infrastructure/Repositories/LinkRepository.cs | 25 +++++ QRCodeService.sln | 37 ++++++++ .../Application/Commands/CreateLinkCommand.cs | 14 +++ .../Commands/CreateLinkCommandHandler.cs | 18 ++++ .../Queries/GetLinkQueryHandler.cs | 13 +++ .../Application/Queries/ILinkQueries.cs | 13 +++ .../Application/Queries/LinkQueries.cs | 32 +++++++ .../Application/Queries/LinkViewModel.cs | 15 +++ QRCodeService/Controllers/GenController.cs | 58 ++++++++++++ QRCodeService/Controllers/GoController.cs | 34 +++++++ QRCodeService/Controllers/ImageController.cs | 29 ++++++ .../Controllers/PlaygroundController.cs | 35 +++++++ QRCodeService/Extensions/StringExtension.cs | 21 +++++ QRCodeService/Models/GenInputModel.cs | 16 ++++ QRCodeService/Program.cs | 26 ++++++ QRCodeService/Properties/launchSettings.json | 31 +++++++ QRCodeService/QRCodeService.csproj | 26 ++++++ QRCodeService/QRCodeService.csproj.user | 11 +++ QRCodeService/Startup.cs | 56 +++++++++++ QRCodeService/appsettings.Development.json | 9 ++ QRCodeService/appsettings.json | 10 ++ 35 files changed, 938 insertions(+) create mode 100644 .gitignore create mode 100644 Domain/AggregateModel/AppAggregate/App.cs create mode 100644 Domain/AggregateModel/AppAggregate/IAppRepository.cs create mode 100644 Domain/AggregateModel/LinkAggregate/ILinkRepository.cs create mode 100644 Domain/AggregateModel/LinkAggregate/Link.cs create mode 100644 Domain/Domain.csproj create mode 100644 Domain/SeedWork/Entity.cs create mode 100644 Domain/SeedWork/Enumeration.cs create mode 100644 Domain/SeedWork/IAggregateRoot.cs create mode 100644 Domain/SeedWork/IRepository.cs create mode 100644 Domain/SeedWork/IUnitOfWork.cs create mode 100644 Domain/SeedWork/ValueObject.cs create mode 100644 Infrastructure/Infrastructure.csproj create mode 100644 Infrastructure/Repositories/AppRepository.cs create mode 100644 Infrastructure/Repositories/LinkRepository.cs create mode 100644 QRCodeService.sln create mode 100644 QRCodeService/Application/Commands/CreateLinkCommand.cs create mode 100644 QRCodeService/Application/Commands/CreateLinkCommandHandler.cs create mode 100644 QRCodeService/Application/Queries/GetLinkQueryHandler.cs create mode 100644 QRCodeService/Application/Queries/ILinkQueries.cs create mode 100644 QRCodeService/Application/Queries/LinkQueries.cs create mode 100644 QRCodeService/Application/Queries/LinkViewModel.cs create mode 100644 QRCodeService/Controllers/GenController.cs create mode 100644 QRCodeService/Controllers/GoController.cs create mode 100644 QRCodeService/Controllers/ImageController.cs create mode 100644 QRCodeService/Controllers/PlaygroundController.cs create mode 100644 QRCodeService/Extensions/StringExtension.cs create mode 100644 QRCodeService/Models/GenInputModel.cs create mode 100644 QRCodeService/Program.cs create mode 100644 QRCodeService/Properties/launchSettings.json create mode 100644 QRCodeService/QRCodeService.csproj create mode 100644 QRCodeService/QRCodeService.csproj.user create mode 100644 QRCodeService/Startup.cs create mode 100644 QRCodeService/appsettings.Development.json create mode 100644 QRCodeService/appsettings.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..edff6a8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.vs/ +Domain/bin/ +Domain/obj/ +Infrastructure/bin/ +Infrastructure/obj/ +QRCodeService/bin/ +QRCodeService/obj/ diff --git a/Domain/AggregateModel/AppAggregate/App.cs b/Domain/AggregateModel/AppAggregate/App.cs new file mode 100644 index 0000000..1b29f10 --- /dev/null +++ b/Domain/AggregateModel/AppAggregate/App.cs @@ -0,0 +1,23 @@ +using Domain.SeedWork; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Domain.AggregateModel.AppAggregate +{ + public class App : IAggregateRoot + { + public int Id { get; private set; } + public string AppKey { get;private set; } + public string BaseUrl { get; private set; } + public string Remarks { get;private set; } + private App() { } + public App(string appKey,string remarks) + { + AppKey = appKey; + Remarks = remarks; + } + } +} diff --git a/Domain/AggregateModel/AppAggregate/IAppRepository.cs b/Domain/AggregateModel/AppAggregate/IAppRepository.cs new file mode 100644 index 0000000..93a614a --- /dev/null +++ b/Domain/AggregateModel/AppAggregate/IAppRepository.cs @@ -0,0 +1,15 @@ +using Domain.SeedWork; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Domain.AggregateModel.AppAggregate +{ + public interface IAppRepository:IRepository + { + void Add(App app); + Task GetAsync(int id); + } +} diff --git a/Domain/AggregateModel/LinkAggregate/ILinkRepository.cs b/Domain/AggregateModel/LinkAggregate/ILinkRepository.cs new file mode 100644 index 0000000..f265131 --- /dev/null +++ b/Domain/AggregateModel/LinkAggregate/ILinkRepository.cs @@ -0,0 +1,16 @@ +using Domain.SeedWork; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Domain.AggregateModel.LinkAggregate +{ + public interface ILinkRepository:IRepository + { + void Add(Link link); + + Task GetAsync(string shortCode); + } +} diff --git a/Domain/AggregateModel/LinkAggregate/Link.cs b/Domain/AggregateModel/LinkAggregate/Link.cs new file mode 100644 index 0000000..ee92e77 --- /dev/null +++ b/Domain/AggregateModel/LinkAggregate/Link.cs @@ -0,0 +1,61 @@ +using Base62; +using Domain.SeedWork; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace Domain.AggregateModel.LinkAggregate +{ + public class Link:IAggregateRoot + { + /// + /// 非自增主键 + /// + public string ShortCode { get; private set; } + public string BaseUrl { get; private set; } + public string SuffixUrl { get; private set; } + public string FullUrl { get; private set; } + public int AppId { get; private set; } + public DateTime Time { get; private set; } + + private Link() + { + + } + /// + /// 创建一条新的短链接 + /// + /// + /// + /// 分配的应用id + public Link(string baseUrl,string suffixUrl,int appId) + { + BaseUrl = baseUrl; + SuffixUrl = suffixUrl; + FullUrl = new Uri(new Uri(baseUrl),suffixUrl).ToString(); + AppId = appId; + Time = DateTime.Now; + CalculateShortCode(); + } + /// + /// 根据值计算短链字段 + /// + /// + private void CalculateShortCode() + { + string code; + using (var md5 = MD5.Create()) + { + var result = md5.ComputeHash(Encoding.UTF8.GetBytes(FullUrl)); + var res = new[] { BitConverter.ToInt64(result, 0) ,BitConverter.ToInt64(result,8)}; + //任意取其中一条即可 + code = res[new Random().Next(0,1)].ToBase62(); + } + ShortCode = code; + } + } +} diff --git a/Domain/Domain.csproj b/Domain/Domain.csproj new file mode 100644 index 0000000..60a2896 --- /dev/null +++ b/Domain/Domain.csproj @@ -0,0 +1,12 @@ + + + + netstandard2.0 + + + + + + + + diff --git a/Domain/SeedWork/Entity.cs b/Domain/SeedWork/Entity.cs new file mode 100644 index 0000000..0dd4d54 --- /dev/null +++ b/Domain/SeedWork/Entity.cs @@ -0,0 +1,92 @@ +using MediatR; +using System; +using System.Collections.Generic; + +namespace Domain.SeedWork +{ + public abstract class Entity + { + int? _requestedHashCode; + int _Id; + public virtual int Id + { + get + { + return _Id; + } + protected set + { + _Id = value; + } + } + + private List _domainEvents; + public IReadOnlyCollection DomainEvents => _domainEvents?.AsReadOnly(); + + public void AddDomainEvent(INotification eventItem) + { + _domainEvents = _domainEvents ?? new List(); + _domainEvents.Add(eventItem); + } + + public void RemoveDomainEvent(INotification eventItem) + { + _domainEvents?.Remove(eventItem); + } + + public void ClearDomainEvents() + { + _domainEvents?.Clear(); + } + + public bool IsTransient() + { + return Id == default; + } + + public override bool Equals(object obj) + { + if (obj == null || !(obj is Entity)) + return false; + + if (ReferenceEquals(this, obj)) + return true; + + if (this.GetType() != obj.GetType()) + return false; + + Entity item = (Entity)obj; + + if (item.IsTransient() || this.IsTransient()) + return false; + else + return item.Id == this.Id; + } + + public override int GetHashCode() + { + if (!IsTransient()) + { + if (!_requestedHashCode.HasValue) + _requestedHashCode = this.Id.GetHashCode() ^ 31; // XOR for random distribution (http://blogs.msdn.com/b/ericlippert/archive/2011/02/28/guidelines-and-rules-for-gethashcode.aspx) + + return _requestedHashCode.Value; + } + else + return base.GetHashCode(); + + } + public static bool operator ==(Entity left, Entity right) + { + if (Object.Equals(left, null)) + return (Object.Equals(right, null)) ? true : false; + else + return left.Equals(right); + } + + public static bool operator !=(Entity left, Entity right) + { + return !(left == right); + } + } +} diff --git a/Domain/SeedWork/Enumeration.cs b/Domain/SeedWork/Enumeration.cs new file mode 100644 index 0000000..390a390 --- /dev/null +++ b/Domain/SeedWork/Enumeration.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace Domain.SeedWork +{ + public abstract class Enumeration : IComparable + { + public string Name { get; private set; } + + public int Id { get; private set; } + + protected Enumeration(int id, string name) + { + Id = id; + Name = name; + } + + public override string ToString() => Name; + + public static IEnumerable GetAll() where T : Enumeration + { + var fields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly); + + return fields.Select(f => f.GetValue(null)).Cast(); + } + + public override bool Equals(object obj) + { + var otherValue = obj as Enumeration; + + if (otherValue == null) + return false; + + var typeMatches = GetType().Equals(obj.GetType()); + var valueMatches = Id.Equals(otherValue.Id); + + return typeMatches && valueMatches; + } + + public override int GetHashCode() => Id.GetHashCode(); + + public static int AbsoluteDifference(Enumeration firstValue, Enumeration secondValue) + { + var absoluteDifference = Math.Abs(firstValue.Id - secondValue.Id); + return absoluteDifference; + } + + public static T FromValue(int value) where T : Enumeration + { + var matchingItem = Parse(value, "value", item => item.Id == value); + return matchingItem; + } + + public static T FromDisplayName(string displayName) where T : Enumeration + { + var matchingItem = Parse(displayName, "display name", item => item.Name == displayName); + return matchingItem; + } + + private static T Parse(K value, string description, Func predicate) where T : Enumeration + { + var matchingItem = GetAll().FirstOrDefault(predicate); + + if (matchingItem == null) + throw new InvalidOperationException($"'{value}' is not a valid {description} in {typeof(T)}"); + + return matchingItem; + } + + public int CompareTo(object other) => Id.CompareTo(((Enumeration)other).Id); + } +} diff --git a/Domain/SeedWork/IAggregateRoot.cs b/Domain/SeedWork/IAggregateRoot.cs new file mode 100644 index 0000000..a2444f2 --- /dev/null +++ b/Domain/SeedWork/IAggregateRoot.cs @@ -0,0 +1,6 @@ +namespace Domain.SeedWork +{ + public interface IAggregateRoot + { + } +} diff --git a/Domain/SeedWork/IRepository.cs b/Domain/SeedWork/IRepository.cs new file mode 100644 index 0000000..5d4b92b --- /dev/null +++ b/Domain/SeedWork/IRepository.cs @@ -0,0 +1,7 @@ +namespace Domain.SeedWork +{ + public interface IRepository where T : IAggregateRoot + { + IUnitOfWork UnitOfWork { get; } + } +} diff --git a/Domain/SeedWork/IUnitOfWork.cs b/Domain/SeedWork/IUnitOfWork.cs new file mode 100644 index 0000000..fbb80f3 --- /dev/null +++ b/Domain/SeedWork/IUnitOfWork.cs @@ -0,0 +1,12 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Domain.SeedWork +{ + public interface IUnitOfWork : IDisposable + { + Task SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken)); + Task SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/Domain/SeedWork/ValueObject.cs b/Domain/SeedWork/ValueObject.cs new file mode 100644 index 0000000..fb37962 --- /dev/null +++ b/Domain/SeedWork/ValueObject.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Domain.SeedWork +{ + public abstract class ValueObject + { + protected static bool EqualOperator(ValueObject left, ValueObject right) + { + if (ReferenceEquals(left, null) ^ ReferenceEquals(right, null)) + { + return false; + } + return ReferenceEquals(left, null) || left.Equals(right); + } + + protected static bool NotEqualOperator(ValueObject left, ValueObject right) + { + return !(EqualOperator(left, right)); + } + + protected abstract IEnumerable GetEqualityComponents(); + + public override bool Equals(object obj) + { + if (obj == null || obj.GetType() != GetType()) + { + return false; + } + + var other = (ValueObject)obj; + + return this.GetEqualityComponents().SequenceEqual(other.GetEqualityComponents()); + } + + public override int GetHashCode() + { + return GetEqualityComponents() + .Select(x => x != null ? x.GetHashCode() : 0) + .Aggregate((x, y) => x ^ y); + } + + public ValueObject GetCopy() + { + return this.MemberwiseClone() as ValueObject; + } + } +} diff --git a/Infrastructure/Infrastructure.csproj b/Infrastructure/Infrastructure.csproj new file mode 100644 index 0000000..ee2d94c --- /dev/null +++ b/Infrastructure/Infrastructure.csproj @@ -0,0 +1,11 @@ + + + + netstandard2.0 + + + + + + + diff --git a/Infrastructure/Repositories/AppRepository.cs b/Infrastructure/Repositories/AppRepository.cs new file mode 100644 index 0000000..fe747db --- /dev/null +++ b/Infrastructure/Repositories/AppRepository.cs @@ -0,0 +1,25 @@ +using Domain.AggregateModel.AppAggregate; +using Domain.SeedWork; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Infrastructure.Repositories +{ + public class AppRepository : IAppRepository + { + public IUnitOfWork UnitOfWork => throw new NotImplementedException(); + + public void Add(App app) + { + throw new NotImplementedException(); + } + + public Task GetAsync(int id) + { + throw new NotImplementedException(); + } + } +} diff --git a/Infrastructure/Repositories/LinkRepository.cs b/Infrastructure/Repositories/LinkRepository.cs new file mode 100644 index 0000000..c899e2b --- /dev/null +++ b/Infrastructure/Repositories/LinkRepository.cs @@ -0,0 +1,25 @@ +using Domain.AggregateModel.LinkAggregate; +using Domain.SeedWork; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Infrastructure.Repositories +{ + public class LinkRepository : ILinkRepository + { + public IUnitOfWork UnitOfWork => throw new NotImplementedException(); + + public void Add(Link link) + { + throw new NotImplementedException(); + } + + public Task GetAsync(string shortCode) + { + throw new NotImplementedException(); + } + } +} diff --git a/QRCodeService.sln b/QRCodeService.sln new file mode 100644 index 0000000..6e3e5b2 --- /dev/null +++ b/QRCodeService.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30804.86 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QRCodeService", "QRCodeService\QRCodeService.csproj", "{CF4EF394-9502-4720-8E32-30132C5A7B40}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Domain", "Domain\Domain.csproj", "{FB39ABD1-A7B6-479D-9552-D81D8360E48B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure", "Infrastructure\Infrastructure.csproj", "{3A7EB8BC-4099-461F-9E2D-D34AEC5FC056}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CF4EF394-9502-4720-8E32-30132C5A7B40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF4EF394-9502-4720-8E32-30132C5A7B40}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF4EF394-9502-4720-8E32-30132C5A7B40}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF4EF394-9502-4720-8E32-30132C5A7B40}.Release|Any CPU.Build.0 = Release|Any CPU + {FB39ABD1-A7B6-479D-9552-D81D8360E48B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FB39ABD1-A7B6-479D-9552-D81D8360E48B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FB39ABD1-A7B6-479D-9552-D81D8360E48B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FB39ABD1-A7B6-479D-9552-D81D8360E48B}.Release|Any CPU.Build.0 = Release|Any CPU + {3A7EB8BC-4099-461F-9E2D-D34AEC5FC056}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3A7EB8BC-4099-461F-9E2D-D34AEC5FC056}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3A7EB8BC-4099-461F-9E2D-D34AEC5FC056}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3A7EB8BC-4099-461F-9E2D-D34AEC5FC056}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {BF393BCC-5055-4752-A4D8-DF51E9A215AE} + EndGlobalSection +EndGlobal diff --git a/QRCodeService/Application/Commands/CreateLinkCommand.cs b/QRCodeService/Application/Commands/CreateLinkCommand.cs new file mode 100644 index 0000000..9f7315c --- /dev/null +++ b/QRCodeService/Application/Commands/CreateLinkCommand.cs @@ -0,0 +1,14 @@ +using MediatR; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace QRCodeService.Application.Commands +{ + public class CreateLinkCommand : IRequest + { + + } +} diff --git a/QRCodeService/Application/Commands/CreateLinkCommandHandler.cs b/QRCodeService/Application/Commands/CreateLinkCommandHandler.cs new file mode 100644 index 0000000..3eb44d8 --- /dev/null +++ b/QRCodeService/Application/Commands/CreateLinkCommandHandler.cs @@ -0,0 +1,18 @@ +using MediatR; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace QRCodeService.Application.Commands +{ + public class CreateLinkCommandHandler : IRequestHandler + { + public Task Handle(CreateLinkCommand request, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + } +} diff --git a/QRCodeService/Application/Queries/GetLinkQueryHandler.cs b/QRCodeService/Application/Queries/GetLinkQueryHandler.cs new file mode 100644 index 0000000..b8a5469 --- /dev/null +++ b/QRCodeService/Application/Queries/GetLinkQueryHandler.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace QRCodeService.Application.Queries +{ + public class GetLinkQueryHandler + { + + } +} diff --git a/QRCodeService/Application/Queries/ILinkQueries.cs b/QRCodeService/Application/Queries/ILinkQueries.cs new file mode 100644 index 0000000..1a61e97 --- /dev/null +++ b/QRCodeService/Application/Queries/ILinkQueries.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace QRCodeService.Application.Queries +{ + public interface ILinkQueries + { + Task GetLinkAsync(string shortCode); + } +} diff --git a/QRCodeService/Application/Queries/LinkQueries.cs b/QRCodeService/Application/Queries/LinkQueries.cs new file mode 100644 index 0000000..17393c3 --- /dev/null +++ b/QRCodeService/Application/Queries/LinkQueries.cs @@ -0,0 +1,32 @@ +using MediatR; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Dapper; +using MySqlConnector; + +namespace QRCodeService.Application.Queries +{ + public class LinkQueries : ILinkQueries + { + readonly string _connectionString; + + public LinkQueries(string connectionString) + { + _connectionString = connectionString; + } + + public async Task GetLinkAsync(string shortCode) + { + using(var connection = new MySqlConnection(_connectionString)) + { + connection.Open(); + var link = await connection.QueryAsync( + @"SELECT A FROM B WHERE ShortCode = @shortCode",new {shortCode }); + return link.Single(); + } + } + } +} diff --git a/QRCodeService/Application/Queries/LinkViewModel.cs b/QRCodeService/Application/Queries/LinkViewModel.cs new file mode 100644 index 0000000..07f566d --- /dev/null +++ b/QRCodeService/Application/Queries/LinkViewModel.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace QRCodeService.Application.Queries +{ + public class Link + { + public string ShortCode { get; set; } + + public string FullUrl { get; set; } + } +} diff --git a/QRCodeService/Controllers/GenController.cs b/QRCodeService/Controllers/GenController.cs new file mode 100644 index 0000000..0e7a8a9 --- /dev/null +++ b/QRCodeService/Controllers/GenController.cs @@ -0,0 +1,58 @@ +using Domain.AggregateModel.LinkAggregate; +using Microsoft.AspNetCore.Mvc; +using QRCodeService.Models; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Security.Cryptography; +using Domain.AggregateModel.AppAggregate; +using Base62; +using QRCodeService.Extensions; + +namespace QRCodeService.Controllers +{ + /// + /// 生成二维码图片 + /// + [Route("api/[controller]")] + [ApiController] + public class GenController:ControllerBase + { + readonly ILinkRepository linkRepository; + readonly IAppRepository appRepository; + + public GenController(ILinkRepository linkRepository, IAppRepository appRepository) + { + this.linkRepository = linkRepository; + this.appRepository = appRepository; + } + + [HttpPost] + public async Task CreateLink(GenInputModel model) + { + + var app = await appRepository.GetAsync(model.AppId); + if (app == null) + { + return BadRequest(); + } + using(var md5 = MD5.Create()) + { + var result = md5.ComputeHash(Encoding.UTF8.GetBytes($"{model.AppId}{model.SuffixUrl}{model.Time}{app.AppKey}")); + var sign = BitConverter.ToString(result); + if (sign != model.Sign) + { + return BadRequest(); + } + } + var shortCode = $"{model.SuffixUrl}".ToMD5().ToBase62(); + var link = new Link(app.BaseUrl, model.SuffixUrl,1); + linkRepository.Add(link); + await linkRepository.UnitOfWork.SaveEntitiesAsync(); + return Ok(link.ShortCode); + } + } +} diff --git a/QRCodeService/Controllers/GoController.cs b/QRCodeService/Controllers/GoController.cs new file mode 100644 index 0000000..4011744 --- /dev/null +++ b/QRCodeService/Controllers/GoController.cs @@ -0,0 +1,34 @@ +using Domain.AggregateModel.LinkAggregate; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace QRCodeService.Controllers +{ + /// + /// 跳转url请求的地址 + /// + [Route("{shortCode}")] + [ApiController] + public class GoController: ControllerBase + { + readonly ILinkRepository LinkRepository; + public GoController(ILinkRepository linkRepository) + { + LinkRepository = linkRepository; + } + [HttpGet] + public async Task Get(string shortcode) + { + var link = await LinkRepository.GetAsync(shortcode); + if (link == null) + { + return NotFound(); + } + return Redirect(link.FullUrl); + } + } +} diff --git a/QRCodeService/Controllers/ImageController.cs b/QRCodeService/Controllers/ImageController.cs new file mode 100644 index 0000000..447ebb8 --- /dev/null +++ b/QRCodeService/Controllers/ImageController.cs @@ -0,0 +1,29 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using QRCoder; +using System.IO; + +namespace QRCodeService.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class ImageController : ControllerBase + { + [Route("{shortCode}")] + public IActionResult Get(string shortCode) + { + var qrCodeGenerator = new QRCodeGenerator(); + var data = qrCodeGenerator.CreateQrCode("www.baidu.com", QRCodeGenerator.ECCLevel.Q); + var qrCode = new QRCode(data); + using (var stream = new MemoryStream()) + { + qrCode.GetGraphic(20).Save(stream, System.Drawing.Imaging.ImageFormat.Png); + return File(stream.ToArray(), "image/png", "qrcode.png"); + } + } + } +} diff --git a/QRCodeService/Controllers/PlaygroundController.cs b/QRCodeService/Controllers/PlaygroundController.cs new file mode 100644 index 0000000..391339f --- /dev/null +++ b/QRCodeService/Controllers/PlaygroundController.cs @@ -0,0 +1,35 @@ +using Base62; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace QRCodeService.Controllers +{ + [Route("[controller]/[action]")] + public class PlaygroundController:ControllerBase + { + public IActionResult GenShortCode(string url) + { + var codes = new string[2]; + using (var md5 = MD5.Create()) + { + var chunkSize = 8; + var result = md5.ComputeHash(Encoding.UTF8.GetBytes(url)); + for (int i = 0; i < 2; i++) + { + var first = result.Take(chunkSize).ToArray(); + //即超过30位的忽略处理 + var res = BitConverter.ToInt64(first); + var code = res.ToBase62(); + codes[i] = code; + result = result.Skip(chunkSize).ToArray(); + } + return Ok(codes); + } + } + } +} diff --git a/QRCodeService/Extensions/StringExtension.cs b/QRCodeService/Extensions/StringExtension.cs new file mode 100644 index 0000000..bc24862 --- /dev/null +++ b/QRCodeService/Extensions/StringExtension.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace QRCodeService.Extensions +{ + public static class StringExtension + { + public static byte[] ToMD5(this string value) + { + using (var md5 = MD5.Create()) + { + var result = md5.ComputeHash(Encoding.UTF8.GetBytes(value)); + return result; + } + } + } +} diff --git a/QRCodeService/Models/GenInputModel.cs b/QRCodeService/Models/GenInputModel.cs new file mode 100644 index 0000000..e7975dd --- /dev/null +++ b/QRCodeService/Models/GenInputModel.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace QRCodeService.Models +{ + public class GenInputModel + { + public int AppId { get; set; } + public string Time { get; set; } + public string SuffixUrl { get; set; } + public string Sign { get; set; } + } +} diff --git a/QRCodeService/Program.cs b/QRCodeService/Program.cs new file mode 100644 index 0000000..050fb85 --- /dev/null +++ b/QRCodeService/Program.cs @@ -0,0 +1,26 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace QRCodeService +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + } +} diff --git a/QRCodeService/Properties/launchSettings.json b/QRCodeService/Properties/launchSettings.json new file mode 100644 index 0000000..e5e9f8a --- /dev/null +++ b/QRCodeService/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:58886", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "QRCodeService": { + "commandName": "Project", + "dotnetRunMessages": "true", + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/QRCodeService/QRCodeService.csproj b/QRCodeService/QRCodeService.csproj new file mode 100644 index 0000000..c3af3a4 --- /dev/null +++ b/QRCodeService/QRCodeService.csproj @@ -0,0 +1,26 @@ + + + + net5.0 + + + + + + + + + + + + + + + + + + + + + + diff --git a/QRCodeService/QRCodeService.csproj.user b/QRCodeService/QRCodeService.csproj.user new file mode 100644 index 0000000..d1f541e --- /dev/null +++ b/QRCodeService/QRCodeService.csproj.user @@ -0,0 +1,11 @@ + + + + ProjectDebugger + + + QRCodeService + ApiControllerEmptyScaffolder + root/Common/Api + + \ No newline at end of file diff --git a/QRCodeService/Startup.cs b/QRCodeService/Startup.cs new file mode 100644 index 0000000..7f17ce6 --- /dev/null +++ b/QRCodeService/Startup.cs @@ -0,0 +1,56 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.OpenApi.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace QRCodeService +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + + services.AddControllers(); + services.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new OpenApiInfo { Title = "QRCodeService", Version = "v1" }); + }); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + app.UseSwagger(); + app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "QRCodeService v1")); + } + + app.UseRouting(); + + app.UseAuthorization(); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + } + } +} diff --git a/QRCodeService/appsettings.Development.json b/QRCodeService/appsettings.Development.json new file mode 100644 index 0000000..8983e0f --- /dev/null +++ b/QRCodeService/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/QRCodeService/appsettings.json b/QRCodeService/appsettings.json new file mode 100644 index 0000000..d9d9a9b --- /dev/null +++ b/QRCodeService/appsettings.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*" +}