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 中,修改如下代码:

csharp 复制代码
 .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,如下:

csharp 复制代码
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_0
        converters.Add(new NewtonsoftJsonDateOnlyJsonConverter());
        converters.Add(new NewtonsoftJsonNullableDateOnlyJsonConverter());
#endif
        return converters;
    }

    /// <summary>
    /// 添加 TimeOnly/TimeOnly? 类型序列化处理
    /// </summary>
    /// <param name="converters"></param>
    /// <returns></returns>
    public static IList<JsonConverter> AddTimeOnlyConverters(this IList<JsonConverter> converters)
    {
#if !NET5_0
        converters.Add(new NewtonsoftJsonTimeOnlyJsonConverter());
        converters.Add(new NewtonsoftJsonNullableTimeOnlyJsonConverter());
#endif
        return converters;
    }
}

RuoYi.Framework\JsonSerialization\Converters\NewtonsoftJson\NewtonsoftJsonLongToStringJsonConverter.cs,如下:

csharp 复制代码
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());
        }
    }
}
相关推荐
海鸥-w1 天前
数据库冗余字段设计笔记
java·数据库·笔记·oracle
咚咚咚小柒2 天前
【前端】LangChain.js学习
前端·javascript·人工智能·typescript·langchain·vue·ai编程
实泽有之,无泽虚之2 天前
ORA-12514:TNS:监听程序当前无法识别连接描述符中请求的服务问题原因及解决办法
数据库·oracle
程序员塔塔喵2 天前
【MySQL篇|第十篇】深分页问题
数据库·oracle·深分页问题
qq_452396232 天前
第八篇:《VACUUM、自动清理与膨胀治理》
jvm·数据库·oracle
晴天¥2 天前
记录Oracle11g数据库OGG同步实验
oracle·oracle ogg·oracle高可用架构
晴天¥2 天前
Oracle集群中是该如何管理控制文件和日志文件组?
数据库·oracle
Thanks_ks2 天前
从 0.1+0.2 不等于 0.3 说起:聊聊浮点数精度问题
java·python·数值计算·精度丢失·bigdecimal·浮点数·ieee754
云策数链2 天前
用友 T+Cloud / U8 项目交接时的账套健康度核查清单
数据库·oracle·erp·用友·云策数链
jnrjian2 天前
Oracle RAC crs stop时force 关闭DB,另一个node会立即进行recover
数据库·oracle