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());
        }
    }
}
相关推荐
oradh1 天前
Oracle固定执行计划的方法---SQL Plan Baseline
数据库·sql·oracle
杨云龙UP1 天前
Oracle 19c ADG 实时同步故障排查与修复:Standby Redo Log(SRL)文件缺失导致备库仅在主库归档后同步
数据库·oracle·adg·data guard·srl·ora-00313·ora-27037
SmartSoftHelp开发辅助优化1 天前
SmartSoftHelp DeepCore XSuite Pro Global Eco AIAgent 2026.V29 专业国际版
数据库·oracle
zxcvb1531 天前
规定备份信息的备份方式:从策略制定到自动化落地的实践思考
运维·oracle·自动化
骑着蜗牛撵大象3271 天前
SpringBoot+Vue3 企业智能体侧挂架构:独立服务、独立数据库与主线零侵入落地
数据库·spring boot·架构·vue·springboot·事件驱动·服务拆分
杨云龙UP2 天前
Oracle 19c 单机到单机 Active Data Guard 搭建与巡检操作手册
数据库·oracle·adg·操作指南·data guard·dg搭建
我科绝伦(Huanhuan Zhou)2 天前
oracle坏块导致备份不了
数据库·oracle·ffmpeg
杨云龙UP2 天前
Oracle 19c RAC到RAC Active Data Guard标准搭建与巡检指南
运维·服务器·数据库·oracle·adg·data guard·rac到rac
许彰午2 天前
06-Oracle卸载与重装完整流程
数据库·oracle
我的xiaodoujiao2 天前
Django 基础知识详细图文教程 13-Django 模型定义与使用 3
数据库·后端·python·测试工具·oracle·django