RuoYi.Net后端返回雪花ID前端精度丢失问题
遇到问题:
RuoYi.Net
使用 Oracle
库,SYS_MENU
菜单表的 MENU_ID
创建为 NUMBER(19)
类型,Vue
前端新增菜单保存到数据库的 MENU_ID
,以及后端返回给前端的 MENU_ID
没问题(ORM
使用的是SqlSugar,SqlSugar
新增入库时如果主键为 long
类型则自动生成雪花ID
),但在前端显示时发现精度丢失,如下:
数据库中 MENUID
为 1978349139955683328
前端显示 MENUID
为 1978349139955683300
解决办法:
参见 SqlSugar
官网: https://www.donet5.com/Doc/8nuge/2561
或者在 RuoYi.Admin\Startup.cs
中,修改如下代码:
.AddNewtonsoftJson(options =>{// 忽略循环引用options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";// 忽略所有 null 属性//options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;// long 类型序列化时转 string, 防止 JavaScript 出现精度溢出问题options.SerializerSettings.Converters.AddLongTypeConverters(); // 这一行扩展方法})
RuoYi.Framework\JsonSerialization\Extensions\NewtonsoftJsonExtensions.cs,如下:
using RuoYi.Framework.JsonSerialization;namespace Newtonsoft.Json;/// <summary>
/// Newtonsoft.Json 拓展
/// </summary>
[SuppressSniffer]
public static class NewtonsoftJsonExtensions
{/// <summary>/// 添加 DateTime/DateTime?/DateTimeOffset/DateTimeOffset? 类型序列化处理/// </summary>/// <param name="converters"></param>/// <param name="outputFormat"></param>/// <param name="localized">自动转换 DateTimeOffset 为当地时间</param>/// <returns></returns>public static IList<JsonConverter> AddDateTimeTypeConverters(this IList<JsonConverter> converters, string outputFormat = "yyyy-MM-dd HH:mm:ss", bool localized = false){converters.Add(new NewtonsoftJsonDateTimeJsonConverter(outputFormat));converters.Add(new NewtonsoftNullableJsonDateTimeJsonConverter(outputFormat));converters.Add(new NewtonsoftJsonDateTimeOffsetJsonConverter(outputFormat, localized));converters.Add(new NewtonsoftJsonNullableDateTimeOffsetJsonConverter(outputFormat, localized));return converters;}/// <summary>/// 添加 long/long? 类型序列化处理/// </summary>/// <param name="converters"></param>/// <param name="overMaxLengthOf17">是否超过最大长度 17 再处理</param>/// <remarks></remarks>public static IList<JsonConverter> AddLongTypeConverters(this IList<JsonConverter> converters, bool overMaxLengthOf17 = false){converters.Add(new NewtonsoftJsonLongToStringJsonConverter(overMaxLengthOf17));converters.Add(new NewtonsoftJsonNullableLongToStringJsonConverter(overMaxLengthOf17));return converters;}/// <summary>/// 添加 DateOnly/DateOnly? 类型序列化处理/// </summary>/// <param name="converters"></param>/// <returns></returns>public static IList<JsonConverter> AddDateOnlyConverters(this IList<JsonConverter> converters){
#if !NET5_0converters.Add(new NewtonsoftJsonDateOnlyJsonConverter());converters.Add(new NewtonsoftJsonNullableDateOnlyJsonConverter());
#endifreturn converters;}/// <summary>/// 添加 TimeOnly/TimeOnly? 类型序列化处理/// </summary>/// <param name="converters"></param>/// <returns></returns>public static IList<JsonConverter> AddTimeOnlyConverters(this IList<JsonConverter> converters){
#if !NET5_0converters.Add(new NewtonsoftJsonTimeOnlyJsonConverter());converters.Add(new NewtonsoftJsonNullableTimeOnlyJsonConverter());
#endifreturn converters;}
}
RuoYi.Framework\JsonSerialization\Converters\NewtonsoftJson\NewtonsoftJsonLongToStringJsonConverter.cs,如下:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;namespace RuoYi.Framework.JsonSerialization;/// <summary>
/// 解决 long 精度问题
/// </summary>
[SuppressSniffer]
public class NewtonsoftJsonLongToStringJsonConverter : JsonConverter<long>
{/// <summary>/// 构造函数/// </summary>public NewtonsoftJsonLongToStringJsonConverter(){}/// <summary>/// 构造函数/// </summary>/// <param name="overMaxLengthOf17"></param>public NewtonsoftJsonLongToStringJsonConverter(bool overMaxLengthOf17 = false){OverMaxLengthOf17 = overMaxLengthOf17;}/// <summary>/// 是否超过最大长度 17 再处理/// </summary>public bool OverMaxLengthOf17 { get; set; }/// <summary>/// 反序列化/// </summary>/// <param name="reader"></param>/// <param name="objectType"></param>/// <param name="existingValue"></param>/// <param name="hasExistingValue"></param>/// <param name="serializer"></param>/// <returns></returns>public override long ReadJson(JsonReader reader, Type objectType, long existingValue, bool hasExistingValue, JsonSerializer serializer){var jt = JValue.ReadFrom(reader);return jt.Value<long>();}/// <summary>/// 序列化/// </summary>/// <param name="writer"></param>/// <param name="value"></param>/// <param name="serializer"></param>public override void WriteJson(JsonWriter writer, long value, JsonSerializer serializer){if (OverMaxLengthOf17){if (value.ToString().Length <= 17) writer.WriteValue(value);else writer.WriteValue(value.ToString());}else writer.WriteValue(value.ToString());}
}/// <summary>
/// 解决 long? 精度问题
/// </summary>
[SuppressSniffer]
public class NewtonsoftJsonNullableLongToStringJsonConverter : JsonConverter<long?>
{/// <summary>/// 构造函数/// </summary>public NewtonsoftJsonNullableLongToStringJsonConverter(){}/// <summary>/// 构造函数/// </summary>/// <param name="overMaxLengthOf17"></param>public NewtonsoftJsonNullableLongToStringJsonConverter(bool overMaxLengthOf17 = false){OverMaxLengthOf17 = overMaxLengthOf17;}/// <summary>/// 是否超过最大长度 17 再处理/// </summary>public bool OverMaxLengthOf17 { get; set; }/// <summary>/// 反序列化/// </summary>/// <param name="reader"></param>/// <param name="objectType"></param>/// <param name="existingValue"></param>/// <param name="hasExistingValue"></param>/// <param name="serializer"></param>/// <returns></returns>public override long? ReadJson(JsonReader reader, Type objectType, long? existingValue, bool hasExistingValue, JsonSerializer serializer){var jt = JValue.ReadFrom(reader);return jt.Value<long?>();}/// <summary>/// 序列化/// </summary>/// <param name="writer"></param>/// <param name="value"></param>/// <param name="serializer"></param>public override void WriteJson(JsonWriter writer, long? value, JsonSerializer serializer){if (value == null) writer.WriteNull();else{var newValue = value.Value;if (OverMaxLengthOf17){if (newValue.ToString().Length <= 17) writer.WriteValue(newValue);else writer.WriteValue(newValue.ToString());}else writer.WriteValue(newValue.ToString());}}
}