Skip to content

Commit bcb4d17

Browse files
committed
✨✅ 新增SqlSugar和Yitter雪花算法工具类,支持ID与DateTime的转换
1 parent 93559c5 commit bcb4d17

File tree

8 files changed

+199
-23
lines changed

8 files changed

+199
-23
lines changed

Blog.Core.Api/Blog.Core.xml

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Blog.Core.Api/Controllers/ValuesController.cs

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,17 @@ public class ValuesController : BaseApiController
4848
private readonly SeqOptions _seqOptions;
4949
private readonly ICaching _cache;
5050

51-
public ValuesController(IBlogArticleServices blogArticleServices, IMapper mapper, IAdvertisementServices advertisementServices, Love love,
52-
IRoleModulePermissionServices roleModulePermissionServices, IUser user, IPasswordLibServices passwordLibServices,
53-
IHttpPollyHelper httpPollyHelper, IRabbitMQPersistentConnection persistentConnection, IOptions<SeqOptions> seqOptions, ICaching caching)
51+
public ValuesController(IBlogArticleServices blogArticleServices, IMapper mapper,
52+
IAdvertisementServices advertisementServices, Love love,
53+
IRoleModulePermissionServices roleModulePermissionServices, IUser user,
54+
IPasswordLibServices passwordLibServices,
55+
IHttpPollyHelper httpPollyHelper, IRabbitMQPersistentConnection persistentConnection,
56+
IOptions<SeqOptions> seqOptions, ICaching caching)
5457
{
5558
// 测试 Authorize 和 mapper
56-
_mapper = mapper;
57-
_advertisementServices = advertisementServices;
58-
_love = love;
59+
_mapper = mapper;
60+
_advertisementServices = advertisementServices;
61+
_love = love;
5962
_roleModulePermissionServices = roleModulePermissionServices;
6063
// 测试 Httpcontext
6164
_user = user;
@@ -66,10 +69,10 @@ public ValuesController(IBlogArticleServices blogArticleServices, IMapper mapper
6669
// 测试redis消息队列
6770
_blogArticleServices = blogArticleServices;
6871
// httpPolly
69-
_httpPollyHelper = httpPollyHelper;
72+
_httpPollyHelper = httpPollyHelper;
7073
_persistentConnection = persistentConnection;
71-
_cache = caching;
72-
_seqOptions = seqOptions.Value;
74+
_cache = caching;
75+
_seqOptions = seqOptions.Value;
7376
}
7477

7578
/// <summary>
@@ -84,7 +87,8 @@ public IActionResult TestRabbitMqPublish()
8487
_persistentConnection.TryConnect();
8588
}
8689

87-
_persistentConnection.PublishMessage("Hello, RabbitMQ!", exchangeName: "blogcore", routingKey: "myRoutingKey");
90+
_persistentConnection.PublishMessage("Hello, RabbitMQ!", exchangeName: "blogcore",
91+
routingKey: "myRoutingKey");
8892
return Ok();
8993
}
9094

@@ -104,7 +108,8 @@ public IActionResult TestRabbitMqSubscribe()
104108
return Ok();
105109
}
106110

107-
private async Task<bool> Dealer(string exchange, string routingKey, byte[] msgBody, IDictionary<string, object> headers)
111+
private async Task<bool> Dealer(string exchange, string routingKey, byte[] msgBody,
112+
IDictionary<string, object> headers)
108113
{
109114
await Task.CompletedTask;
110115
Console.WriteLine("我是消费者,这里消费了一条信息是:" + Encoding.UTF8.GetString(msgBody));
@@ -120,7 +125,7 @@ public MessageModel<List<ClaimDto>> MyClaims()
120125
response = (_user.GetClaimsIdentity().ToList()).Select(d =>
121126
new ClaimDto
122127
{
123-
Type = d.Type,
128+
Type = d.Type,
124129
Value = d.Value
125130
}
126131
).ToList()
@@ -194,9 +199,9 @@ await _blogArticleServices.QuerySql(
194199

195200
// 测试多个异步执行时间
196201
var roleModuleTask = _roleModulePermissionServices.Query();
197-
var listTask = _advertisementServices.Query();
198-
var ad = await roleModuleTask;
199-
var list = await listTask;
202+
var listTask = _advertisementServices.Query();
203+
var ad = await roleModuleTask;
204+
var list = await listTask;
200205

201206

202207
// 测试service层返回异常
@@ -290,8 +295,8 @@ public MessageModel<List<string>> GetUserInfo(string ClaimType = "jti")
290295
var getUserInfoByToken = _user.GetUserInfoFromToken(ClaimType);
291296
return new MessageModel<List<string>>()
292297
{
293-
success = _user.IsAuthenticated(),
294-
msg = _user.IsAuthenticated() ? _user.Name.ObjToString() : "未登录",
298+
success = _user.IsAuthenticated(),
299+
msg = _user.IsAuthenticated() ? _user.Name.ObjToString() : "未登录",
295300
response = _user.GetClaimValueByType(ClaimType)
296301
};
297302
}
@@ -353,11 +358,11 @@ public object TestPostPara(string name)
353358
public async Task<object> TestMutiDBAPI()
354359
{
355360
// 从主库中,操作blogs
356-
var blogs = await _blogArticleServices.Query(d => d.bID == 1);
361+
var blogs = await _blogArticleServices.Query(d => d.bID == 1);
357362
var addBlog = await _blogArticleServices.Add(new BlogArticle() { });
358363

359364
// 从从库中,操作pwds
360-
var pwds = await _passwordLibServices.Query(d => d.PLID > 0);
365+
var pwds = await _passwordLibServices.Query(d => d.PLID > 0);
361366
var addPwd = await _passwordLibServices.Add(new PasswordLib() { });
362367

363368
return new
@@ -494,6 +499,18 @@ public async Task<MessageModel<string>> TestCacheAsync()
494499

495500
return Success<string>("");
496501
}
502+
503+
/// <summary>
504+
/// 雪花Id To DateTime
505+
/// </summary>
506+
/// <param name="id"></param>
507+
/// <returns></returns>
508+
[HttpGet]
509+
[AllowAnonymous]
510+
public DateTime SnowflakeIdToDateTime(long id)
511+
{
512+
return YitterSnowflakeHelper.GetDateTime(IdGeneratorUtility.GetOptions(), id);
513+
}
497514
}
498515

499516
public class ClaimDto

Blog.Core.Common/Utility/IdGeneratorUtility.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ namespace Blog.Core.Common.Utility;
1111

1212
public class IdGeneratorUtility
1313
{
14+
private static IdGeneratorOptions _options;
15+
1416
private static readonly Lazy<IAutoRegister> AutoRegister = new(() =>
1517
{
1618
var builder = new AutoRegisterBuilder()
@@ -44,16 +46,23 @@ public class IdGeneratorUtility
4446
var config = AutoRegister.Value.Register();
4547

4648
//WorkerId DataCenterId 取值 1-31
47-
var options = new IdGeneratorOptions
48-
{
49-
WorkerId = (ushort)config.WorkerId,
50-
};
49+
var options = GetOptions();
50+
options.WorkerId = (ushort)config.WorkerId;
5151
IIdGenerator idGenInstance = new DefaultIdGenerator(options);
5252
return idGenInstance;
5353
});
5454

5555
private static IIdGenerator IdGenInstance => _idGenInstance.Value;
5656

57+
public static IdGeneratorOptions GetOptions()
58+
{
59+
_options ??= new IdGeneratorOptions
60+
{
61+
};
62+
63+
return _options;
64+
}
65+
5766
public static long NextId()
5867
{
5968
return IdGenInstance.NewLong();
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
namespace Blog.Core.Common.Utility;
2+
3+
/// <summary>
4+
/// SqlSugar 雪花算法 工具类
5+
/// </summary>
6+
public class SqlSugarSnowflakeHelper
7+
{
8+
private const long Twepoch = 1288834974657L;
9+
private const int TimestampLeftShift = 22;
10+
private const int DatacenterIdShift = 17;
11+
private const int WorkerIdShift = 12;
12+
private const long SequenceMask = 0xFFF; // 4095
13+
private const long WorkerMask = 0x1F; // 31
14+
private const long DatacenterMask = 0x1F; // 31
15+
16+
public static DateTime GetDateTime(long id)
17+
{
18+
long timestamp = (id >> TimestampLeftShift) + Twepoch;
19+
return DateTimeOffset.FromUnixTimeMilliseconds(timestamp).ToLocalTime().DateTime;
20+
}
21+
22+
public static (DateTime time, long datacenterId, long workerId, long sequence) Decode(long id)
23+
{
24+
long timestamp = (id >> TimestampLeftShift) + Twepoch;
25+
long datacenterId = (id >> DatacenterIdShift) & DatacenterMask;
26+
long workerId = (id >> WorkerIdShift) & WorkerMask;
27+
long sequence = id & SequenceMask;
28+
var time = DateTimeOffset.FromUnixTimeMilliseconds(timestamp).ToLocalTime().DateTime;
29+
return (time, datacenterId, workerId, sequence);
30+
}
31+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using Yitter.IdGenerator;
2+
3+
namespace Blog.Core.Common.Utility;
4+
5+
/// <summary>
6+
/// Yitter 雪花算法 工具类
7+
/// </summary>
8+
public class YitterSnowflakeHelper
9+
{
10+
/// <summary>
11+
/// 从ID中解析时间
12+
/// </summary>
13+
public static DateTime GetDateTime(IdGeneratorOptions options, long id)
14+
{
15+
int shift = options.SeqBitLength + options.WorkerIdBitLength + options.DataCenterIdBitLength;
16+
long timeDiff = id >> shift;
17+
18+
DateTime utcTime = options.TimestampType == 1
19+
? options.BaseTime.AddSeconds(timeDiff)
20+
: options.BaseTime.AddMilliseconds(timeDiff);
21+
22+
return DateTime.SpecifyKind(utcTime, DateTimeKind.Utc).ToLocalTime();
23+
}
24+
25+
/// <summary>
26+
/// 从ID中解析时间、WorkerId、序列号
27+
/// </summary>
28+
public static (DateTime time, long workerId, long sequence, long datacenterId) Decode(IdGeneratorOptions options,
29+
long id)
30+
{
31+
int seqBits = options.SeqBitLength;
32+
int workerBits = options.WorkerIdBitLength;
33+
int datacenterBits = options.DataCenterIdBitLength;
34+
35+
long sequence = id & ((1L << seqBits) - 1);
36+
long workerId = (id >> seqBits) & ((1L << workerBits) - 1);
37+
long datacenterId = datacenterBits == 0 ? 0 : (id >> (seqBits + workerBits)) & ((1L << datacenterBits) - 1);
38+
long timeDiff = id >> (seqBits + workerBits + datacenterBits);
39+
40+
DateTime utcTime = options.TimestampType == 1
41+
? options.BaseTime.AddSeconds(timeDiff)
42+
: options.BaseTime.AddMilliseconds(timeDiff);
43+
44+
DateTime localTime = DateTime.SpecifyKind(utcTime, DateTimeKind.Utc).ToLocalTime();
45+
46+
return (localTime, workerId, sequence, datacenterId);
47+
}
48+
}

Blog.Core.Tests/Blog.Core.Tests.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
</ItemGroup>
1818

1919
<ItemGroup>
20+
<PackageReference Include="JetBrains.Annotations" Version="2025.2.2" />
2021
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
2122
<PackageReference Include="Moq" Version="4.20.69" />
2223
<PackageReference Include="xunit" Version="2.6.1" />
@@ -28,6 +29,7 @@
2829

2930
<ItemGroup>
3031
<ProjectReference Include="..\Blog.Core.Api\Blog.Core.Api.csproj" />
32+
<ProjectReference Include="..\Blog.Core.Common\Blog.Core.Common.csproj" />
3133
</ItemGroup>
3234

3335
<ItemGroup>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System.Globalization;
2+
using Blog.Core.Common.Utility;
3+
using JetBrains.Annotations;
4+
using SqlSugar;
5+
using SqlSugar.DistributedSystem.Snowflake;
6+
using Xunit;
7+
using Xunit.Abstractions;
8+
9+
namespace Blog.Core.Tests.Utility;
10+
11+
[TestSubject(typeof(SqlSugarSnowflakeHelper))]
12+
public class SqlSugarSnowflakeHelperTest(ITestOutputHelper testOutputHelper)
13+
{
14+
[Fact]
15+
public void Test_Id_To_Datetime()
16+
{
17+
var id = SnowFlakeSingle.Instance.NextId();
18+
19+
testOutputHelper.WriteLine(SqlSugarSnowflakeHelper.GetDateTime(id).ToString(CultureInfo.InvariantCulture));
20+
}
21+
22+
[Fact]
23+
public void Test_Id()
24+
{
25+
var id = SnowFlakeSingle.Instance.NextId();
26+
27+
testOutputHelper.WriteLine(SqlSugarSnowflakeHelper.Decode(id).ToJson());
28+
}
29+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System.Globalization;
2+
using Blog.Core.Common.Utility;
3+
using JetBrains.Annotations;
4+
using Xunit;
5+
using Xunit.Abstractions;
6+
using Yitter.IdGenerator;
7+
8+
namespace Blog.Core.Tests.Utility;
9+
10+
[TestSubject(typeof(YitterSnowflakeHelper))]
11+
public class YitterSnowflakeHelperTest(ITestOutputHelper testOutputHelper)
12+
{
13+
private static readonly IdGeneratorOptions _options = new IdGeneratorOptions { WorkerId = 1 };
14+
private readonly IIdGenerator _idGenInstance = new DefaultIdGenerator(_options);
15+
16+
[Fact]
17+
public void Test_Id_To_Datetime()
18+
{
19+
var id = _idGenInstance.NewLong();
20+
21+
var dateTime = YitterSnowflakeHelper.GetDateTime(_options, id);
22+
testOutputHelper.WriteLine(dateTime.ToString(CultureInfo.InvariantCulture));
23+
}
24+
25+
[Fact]
26+
public void Test_Id()
27+
{
28+
var id = _idGenInstance.NewLong();
29+
30+
var decoded = YitterSnowflakeHelper.Decode(_options, id);
31+
testOutputHelper.WriteLine(decoded.ToJson());
32+
}
33+
}

0 commit comments

Comments
 (0)